app
adom-schematic-viewer
Public Made by Adomby adom
Interactive schematic viewer: your EDA's own render plus per-symbol highlighting and live MPN, stock and price on hover
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
//! adom-schematic-viewer — interactive schematic viewer for a whole `.kicad_sch`.
//!
//! Sibling of adom-layout-viewer. The visual base is the EDA's OWN render
//! (service-kicad `sch/export/svg` — authentic symbols/wires/fonts); we overlay
//! a per-component hotspot layer so hovering a symbol shows what it is plus live
//! stock & price. Meant to be embedded as a live schematic "view" in any app.
mod sexpr;
mod sch_parse;
mod kicad_sch;
mod enrich;
mod server;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use std::fs;
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "adom-schematic-viewer", version, about = "Interactive schematic viewer (.kicad_sch): KiCad-native render + per-component hover with stock & price")]
struct Cli { #[command(subcommand)] command: Cmd }
#[derive(Subcommand)]
enum Cmd {
/// Render a `.kicad_sch` to a composed interactive SVG (+ optional -meta.json).
Render { #[arg(long)] file: PathBuf, #[arg(long)] out: PathBuf, #[arg(long)] meta: bool },
/// Export a self-contained INTERACTIVE HTML for embedding as a schematic view.
Embed { #[arg(long)] file: PathBuf, #[arg(long)] out: Option<PathBuf> },
/// Run the live app server (the embeddable live schematic view).
Serve { #[arg(long)] file: Option<PathBuf>, #[arg(long, default_value_t = 8785)] port: u16 },
/// Look up stock / price / MPN / wiki for one part, as JSON on stdout.
/// Lets a HOST app (e.g. adom-project-manager) serve `/enrich` for an
/// embedded view, which has no server of its own.
Enrich { #[arg(long, default_value = "")] mpn: String, #[arg(long, default_value = "")] lcsc: String },
}
const APP_HTML: &str = include_str!("app.html");
const VIEWER_JS: &str = include_str!("viewer.js");
pub fn build_embed(svg: &str, meta_json: &str) -> String {
let payload = format!(
"<script>window.__SCH__={{svg:{},meta:{}}};</script>\n<script>{}</script>",
serde_json::to_string(svg).unwrap_or_else(|_| "\"\"".into()), meta_json, VIEWER_JS);
APP_HTML.replace(r#"<script src="viewer.js"></script>"#, &payload)
}
fn main() -> Result<()> {
match Cli::parse().command {
Cmd::Render { file, out, meta } => {
let content = fs::read_to_string(&file).with_context(|| format!("read {}", file.display()))?;
let (svg, m) = kicad_sch::render_sheet(&content)?;
fs::write(&out, &svg)?;
eprintln!("[adom-schematic-viewer] {} → {} ({} components)", file.display(), out.display(), m.comp_count);
if meta { fs::write(out.with_extension("meta.json"), serde_json::to_string_pretty(&m)?)?; }
}
Cmd::Embed { file, out } => {
let content = fs::read_to_string(&file).with_context(|| format!("read {}", file.display()))?;
let (svg, m) = kicad_sch::render_sheet(&content)?;
let html = build_embed(&svg, &serde_json::to_string(&m)?);
let out = out.unwrap_or_else(|| file.with_extension("schview.html"));
fs::write(&out, &html)?;
eprintln!("[adom-schematic-viewer] embed → {} ({} components)", out.display(), m.comp_count);
}
Cmd::Serve { file, port } => {
if let Some(f) = file {
let content = fs::read_to_string(&f).with_context(|| format!("read {}", f.display()))?;
let name = f.file_stem().and_then(|s| s.to_str()).unwrap_or("sheet").to_string();
server::load_sch(&name, &content)?;
eprintln!("[adom-schematic-viewer] loaded {}", f.display());
}
server::run(port)?;
}
Cmd::Enrich { mpn, lcsc } => println!("{}", enrich::lookup(&mpn, &lcsc)),
}
Ok(())
}