実行可能セル
実行可能セルは、先頭に metadata comment を持つ通常の MDX code block です。Oxiquill は生成時にその block を抽出し、runtime UI に置き換えます。
Rust セルは build 時に WebAssembly に compile されます。Python セルは browser の Pyodide worker で動きます。Haskell セルは build 時に WASI WebAssembly module に compile されます。3つの言語は同じ input metadata と run mode model を使います。
再実行中も最後に成功した出力を保持し、失敗時にはエラーと再試行操作を併記します。キャンセルや入力不正でも出力を消しません。互換性のあるグラフは同じ canvas を更新し、既定で180msの遷移を使います。OS の動作軽減設定を優先します。style の型・制限と Rust overload は リッチ出力 を参照してください。動的な出力の並びには明示的な artifact ID を推奨します。
Fence と metadata grammar
Section titled “Fence と metadata grammar”interactive fence は rust、python、haskell(Markdown の {.rust} form を含む)を使い、legal backtick/tilde fence と indentation に対応します。metadata は fence 先頭の一つの contiguous な language-specific option-comment block です。Rust は //|////|、Python は #|、Haskell は --| を使います。最初の source line より後にある option 風 comment は source code のままです。
許可される top-level field は次だけで、unknown field は error です。
| Field | Type と rule | Default |
|---|---|---|
id | 必須の lowercase kebab-case ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$。page 内と route scope 後で unique。 | — |
title | cell header に表示する non-empty string。明示した値は前後の空白を除去。 | id |
run | button、reactive、autorun。 | button |
inputs | ^[a-z][a-z0-9_]*$ に一致する lowercase cross-language identifier から input spec への mapping。autorun では禁止。 | {} |
packages | unique non-empty Pyodide package name。Python 専用。 | [] |
crates | cratesDir 直下の helper package name の unique non-empty list。Rust 専用。 | [] |
timeoutMs | 1 以上 2147483647 以下の integer millisecond。 | 30000 |
showSource | initial source visibility を指定する boolean。 | true |
source には metadata 以外の code が必要です。malformed YAML、wrong scalar/collection type、duplicate normalized ID/binding/function、unknown package/crate、language-mismatched dependency field は output を書く前に失敗します。diagnostic は page path、fence start line、可能なら cell ID、正確な field path を含みます。
Haskell cell は standard-library code のみで packages/crates を受け付けません。helper 不要の Rust example では crates: [] を明示します。package/crate list は strict validation 後に deduplicate/sort されます。
Run mode
Section titled “Run mode”button: input と Run button を表示し、mount 時は実行しません。reactive: input を表示して Run button を隠し、mount 時に一度実行します。その後は 150 ms trailing debounce を使い、active execution 一つと最新 replacement 一つだけを保持します。autorun: input/Run button を表示せず、各cell.id + runtimeVersion + sourceについて正確に一度だけ実行します。開発中は runtime-version の更新が先に届いた場合も、source の更新によって前回の実行結果を無効化します。
次の button cell は、input を変更しても明示的に実行するまで待機します。
Rust + Wasm
Explicit button execution
次の autorun cell には実行 control がなく、現在の生成 runtime に対して1回だけ実行されます。
Rust + Wasm
One-time autorun execution
println!("autorun ready");Waiting for the runtime to start.
reactive run が supersede されると、その worker request を active に cancel し、worker recycle の影響を受ける全 request を reject して timer を除去します。debounce 後は最新の complete value だけを実行します。cancellation は execution error として表示されず、stale result は新しい state を上書きしません。timeout/worker fault も同じ deterministic recycle boundary で回復します。unmount は pending/active work を cancel します。
Input schema
Section titled “Input schema”各 input が受け取るのは type に関係する field だけです。共通 field は type、label、description、value。numeric input は min、max、step、integer、select/radio は options も使います。
| Type | Value と constraint |
|---|---|
range, number | finite number。step > 0、min <= max、default が bound 内かつ step grid 上。 |
integer | -2147483648 以上 2147483647 以下の signed 32-bit integer。bound/step も同じ domain。 |
text, textarea | string value。 |
checkbox | boolean value。 |
select, radio | non-empty unique string option または { label, value } object。default は option value と一致。 |
type の default は text、label の default は input name です。description は control と assistive technology 向けに関連付ける optional non-empty string です。default value は checkbox が false、numeric input が 0、text input が空 string です。numeric 専用 field は non-numeric control で拒否され、options は select/radio 以外では使えません。
signed 32-bit integer domain は JavaScript で正確に表現でき、Rust i32、Haskell Int、Python int に同じ値として渡されます。domain 外の integer value、min、max、step は authoring 時に拒否されます。browser control と worker request も、integer: true の numeric input を含めて同じ domain を適用します。
numeric default は browser control と同じ step grid に揃える必要があります。effective step は step があればその値、なければ 1 です。grid の base は min があればその値、なければ明示または default の numeric value です。Oxiquill は不一致の default を丸めたり clamp したりせず、authoring 時に拒否します。
number/integer control は raw edit text と committed runtime value を分離します。空、入力途中、non-finite、range 外、step 不一致の text は表示を保ちますが cell input を更新しません。どれか一つでも invalid なら Run button は disabled になり、reactive execution は validity が戻った後に最新の complete value set を一度だけ実行します。range label の表示精度は step から決まります。
visible label が control の accessible name で、input key は generated language binding にだけ使います。normalization で二つの Rust/Haskell binding が衝突してはなりません。label、description、current value、validation message、grouped control は stable ID で関連付けられ、keyboard focus を表示し、run/error status は focus を奪わず announce されます。
Rust とグラフ
Section titled “Rust とグラフ”この Rust セルは helper crate を使い、slider が変わるたびに plot を再描画します。
Rust + Wasm
Calculate the logistic map with Rust
let steps = u32::try_from(steps).map_err(|_| "steps must be non-negative".to_owned())?;
let points = doc_rust::logistic_series(r, x0, steps).map_err(|error| error.to_string())?;
for point in points.iter().take(5) {
println!("n={} x={:.6}", point.n, point.x);
}
emit_line_plot!(&points, "n", "x");Waiting for the runtime to start.
Rust 入力 UI
Section titled “Rust 入力 UI”crates: [] のセルは helper crate に依存しません。この例では checkbox、select、radio input を使います。
Rust + Wasm
Rust input UI
let base_score = match operation.as_str() {
"triple" => 21_i32,
"double" => 14_i32,
_ => 7_i32,
};
let score = if include_bonus {
base_score + 5
} else {
base_score
};
println!("style = {style}");
println!("score = {score}");Waiting for the runtime to start.
複数 Rust helper crate
Section titled “複数 Rust helper crate”各 Rust セルは必要な helper crate を宣言します。名前は crates/* 配下の Cargo package name と一致させます。
Rust + Wasm
Rust cell with multiple crates
let points = doc_rust::logistic_series(3.2, 0.2, 8).map_err(|error| error.to_string())?;
let final_point = points.last().ok_or_else(|| "series is empty".to_owned())?;
println!("{}", doc_rust_text::labeled_value("final step", final_point.n));
println!("{}", doc_rust_text::labeled_value("final x", format!("{:.6}", final_point.x)));
println!("{}", doc_rust_text::style_note(style.as_str()));Waiting for the runtime to start.
Python 入力
Section titled “Python 入力”Python セルも同じ input metadata を使います。input value は Python 変数として使えます。
Python + Pyodide
Python input UI
values = [1, 2, 3, 4]
if method == "sum":
result = sum(values) * scale
elif method == "max":
result = max(values) * scale
else:
result = sum(values) / len(values) * scale
name = label.upper() if enabled else label
print(f"{name}: {method} = {result}")
print(f"style = {style}")Waiting for the runtime to start.
Haskell 入力
Section titled “Haskell 入力”Haskell セルは --| metadata comment を使います。input value は Haskell 変数になり、putStrLn や print の text output が結果 panel に表示されます。
Haskell + WASI
Haskell input UI
{- Imports may use normal multiline Haskell layout. -}
import Data.List
( intercalate
, sort
)
let base = [1 .. 4 :: Int]
let scaled = map (* factor) base
let displayed = sort (if include_squares then map (\value -> value * value) scaled else scaled)
putStrLn (label ++ ": " ++ intercalate ", " (map show displayed))
putStrLn ("total = " ++ show (sum displayed))Waiting for the runtime to start.
Python の初期化と package 読み込み中は「Python を準備中…」、執筆した code の実行中は「実行中…」と表示します。python.preload による page 単位の先読みは Python runtime asset を参照してください。