import React, { useState, useRef, useCallback } from "react"; import { Upload, FileCode, Plus, Trash2, AlertCircle, CheckCircle2, Settings2, } from "lucide-react"; import { parseYAML, validateYAML, toYAML, PROTOCOLS, DEFAULT_YAML } from "../utils/yamlUtils"; export default function YAMLForm({ onSpecChange, validationErrors }) { const [yamlText, setYamlText] = useState(DEFAULT_YAML); const [parsed, setParsed] = useState(() => parseYAML(DEFAULT_YAML)); const [mode, setMode] = useState("editor"); // editor | parsed | split const [activeTab, setActiveTab] = useState("spec"); // spec | signals | registers const fileRef = useRef(null); const handleChange = useCallback( (text) => { setYamlText(text); try { const obj = parseYAML(text); setParsed(obj); onSpecChange(obj); } catch { // keep previous parsed state } }, [onSpecChange] ); const handleFileUpload = useCallback( (e) => { const file = e.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = (ev) => handleChange(ev.target.result); reader.readAsText(file); }, [handleChange] ); const handlePasteExample = useCallback(() => { handleChange(DEFAULT_YAML); }, [handleChange]); const errors = validateYAML(yamlText); // ── Signal / Register editors ──────────────────────────────────── const updateInterface = (idx, field, value) => { const ifaces = [...(parsed.interfaces || [])]; ifaces[idx] = { ...ifaces[idx], [field]: value }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const addSignal = (ifaceIdx) => { const ifaces = [...(parsed.interfaces || [])]; const existing = Array.isArray(ifaces[ifaceIdx]?.signals) ? ifaces[ifaceIdx].signals : []; const signals = [...existing, { name: "", direction: "input", width: 1 }]; ifaces[ifaceIdx] = { ...ifaces[ifaceIdx], signals }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const updateSignal = (ifaceIdx, sigIdx, field, value) => { const ifaces = [...(parsed.interfaces || [])]; const existing = Array.isArray(ifaces[ifaceIdx]?.signals) ? ifaces[ifaceIdx].signals : []; const signals = [...existing]; signals[sigIdx] = { ...signals[sigIdx], [field]: value }; ifaces[ifaceIdx] = { ...ifaces[ifaceIdx], signals }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const removeSignal = (ifaceIdx, sigIdx) => { const ifaces = [...(parsed.interfaces || [])]; const sigs = Array.isArray(ifaces[ifaceIdx].signals) ? ifaces[ifaceIdx].signals : []; ifaces[ifaceIdx] = { ...ifaces[ifaceIdx], signals: sigs.filter((_, i) => i !== sigIdx), }; const updated = { ...parsed, interfaces: ifaces }; setParsed(updated); handleChange(toYAML(updated)); }; const addRegister = () => { const regs = [...(parsed.registers || []), { name: "", address: "0x00", access: "rw", fields: [] }]; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const updateRegister = (idx, field, value) => { const regs = [...(parsed.registers || [])]; regs[idx] = { ...regs[idx], [field]: value }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const removeRegister = (idx) => { const updated = { ...parsed, registers: parsed.registers.filter((_, i) => i !== idx) }; setParsed(updated); handleChange(toYAML(updated)); }; const addField = (regIdx) => { const regs = [...(parsed.registers || [])]; const fields = [...(regs[regIdx]?.fields || []), { name: "", bits: "0", description: "" }]; regs[regIdx] = { ...regs[regIdx], fields }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const updateField = (regIdx, fldIdx, field, value) => { const regs = [...(parsed.registers || [])]; const fields = [...(regs[regIdx]?.fields || [])]; fields[fldIdx] = { ...fields[fldIdx], [field]: value }; regs[regIdx] = { ...regs[regIdx], fields }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; const removeField = (regIdx, fldIdx) => { const regs = [...(parsed.registers || [])]; regs[regIdx] = { ...regs[regIdx], fields: regs[regIdx].fields.filter((_, i) => i !== fldIdx), }; const updated = { ...parsed, registers: regs }; setParsed(updated); handleChange(toYAML(updated)); }; return (
{e}
))}No interfaces defined. Add one in the Spec tab.
)} {(parsed.interfaces || []).map((iface, iIdx) => (No registers defined.
)} {(parsed.registers || []).map((reg, rIdx) => (