Gleam-inspired typed configuration language (POC)
1//! Build the real Zed guest with Gleam, then leave the component where the
2//! custom wasm linker (`scripts/gleam-wasm-linker`) can install it as the
3//! crate's `cdylib` output (what Zed copies to `extension.wasm`).
4
5use std::env;
6use std::fs;
7use std::path::{Path, PathBuf};
8use std::process::Command;
9
10fn main() {
11 println!("cargo:rerun-if-changed=src/zed_glint.gleam");
12 println!("cargo:rerun-if-changed=gleam.toml");
13 println!("cargo:rerun-if-changed=manifest.toml");
14 println!("cargo:rerun-if-changed=scripts/gleam-wasm-linker");
15 println!("cargo:rerun-if-env-changed=GLEAM");
16
17 let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
18 let gleam = find_gleam(&manifest_dir);
19 eprintln!("zed_glint build.rs: using gleam at {}", gleam.display());
20
21 // Fixed path the linker wrapper reads (relative to package root).
22 let out_wasm = manifest_dir.join("target/gleam-extension.wasm");
23 if let Some(parent) = out_wasm.parent() {
24 fs::create_dir_all(parent).expect("create target/");
25 }
26
27 let status = Command::new(&gleam)
28 .current_dir(&manifest_dir)
29 .args(["export", "zed-extension"])
30 .status()
31 .unwrap_or_else(|err| {
32 panic!(
33 "failed to spawn gleam at {}: {err}\n\
34 Set GLEAM to a wasm-capable gleam binary \
35 (https://tangled.org/nandi.uk/gleam , branch wasm).",
36 gleam.display()
37 )
38 });
39
40 if !status.success() {
41 panic!(
42 "`gleam export zed-extension` failed (status {status}).\n\
43 You need a Gleam build with Zed Wasm support:\n\
44 https://tangled.org/nandi.uk/gleam (branch wasm)\n\
45 cargo build -p gleam\n\
46 export GLEAM=/path/to/gleam/target/debug/gleam\n\
47 Current GLEAM candidate: {}",
48 gleam.display()
49 );
50 }
51
52 // CLI writes package-root extension.wasm; copy to the linker input path.
53 let exported = manifest_dir.join("extension.wasm");
54 if !exported.is_file() {
55 panic!(
56 "gleam export succeeded but {} was not created",
57 exported.display()
58 );
59 }
60 fs::copy(&exported, &out_wasm).unwrap_or_else(|err| {
61 panic!(
62 "copy {} → {}: {err}",
63 exported.display(),
64 out_wasm.display()
65 );
66 });
67
68 eprintln!(
69 "zed_glint build.rs: Gleam component ready at {}",
70 out_wasm.display()
71 );
72}
73
74fn find_gleam(manifest_dir: &Path) -> PathBuf {
75 if let Ok(path) = env::var("GLEAM") {
76 let p = PathBuf::from(path);
77 if p.is_file() {
78 return p;
79 }
80 panic!("GLEAM={p:?} is not a file");
81 }
82
83 // Common local checkouts (glint and gleam as siblings under code/).
84 let candidates = [
85 manifest_dir.join("../../gleam/target/debug/gleam"),
86 manifest_dir.join("../../gleam/target/release/gleam"),
87 manifest_dir.join("../../../gleam/target/debug/gleam"),
88 manifest_dir.join("../../../gleam/target/release/gleam"),
89 ];
90 for candidate in candidates {
91 if candidate.is_file() {
92 return candidate
93 .canonicalize()
94 .unwrap_or(candidate);
95 }
96 }
97
98 // PATH
99 PathBuf::from("gleam")
100}