diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bc0fb..28e84b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,23 @@ user-facing notes live in [`docs/updates/`](docs/updates/) (English and ## Unreleased +### Added + +- Editor: code completion from the SDK itself. `scad.` (and `scad.ql.`, `scad.std.gear.`, `ql.`) + lists the real functions with their signatures and docstrings; accepting one, or typing `(` + after a known name, writes the call with every required parameter as `name=` and Tab moves + between them; inside a call the parameters not given yet complete as `name=` (required first). + The names come from the running package (`GET /api/sdk`), so they cannot drift from the code. +- Editor: a **new** action in the workspace tab starts a notebook from the SDK's template (a part, + or an assembly that uses the first two parts of the workspace), with the name checked as you + type. An empty workspace opens on that form, so `sca edit` on an empty directory is usable. + +### Fixed + +- Editor: the cell editors rebuilt their configuration on every render (a new `onChange` and + `basicSetup` each time), which dropped any snippet in progress and could disturb typing; both + are stable now. + ## 2.2.1 — 2026-10-13 The first stable release of the 2.2 line (2.2.0b1 was a pre-release): everything @@ -21,11 +38,6 @@ below was added since 2.1.4, the notebook runtime of 2.2.0b1 included. ### Added -- Editor: code completion from the SDK itself. `scad.` (and `scad.ql.`, `scad.std.gear.`, `ql.`) - lists the real functions with their signatures and docstrings; accepting one, or typing `(` - after a known name, writes the call with every required parameter as `name=` and Tab moves - between them; inside a call the parameters not given yet complete as `name=` (required first). - The names come from the running package (`GET /api/sdk`), so they cannot drift from the code. - Modeling: `scale`, affine `transform`, signed `offset`, `draft`, tapered and until-limited extrusions and multisection sweeps are recorded features, and boolean results can keep every output of a set operation; graph nodes keep diff --git a/editor-web/src/App.tsx b/editor-web/src/App.tsx index 2d481e4..a19d286 100644 --- a/editor-web/src/App.tsx +++ b/editor-web/src/App.tsx @@ -9,7 +9,7 @@ import { ModuleView, type ModuleState } from "@/components/ModuleView"; import { NotebookList } from "@/components/NotebookList"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { fetchPreview, getWorkspace, openNotebook, postViewport, type ModuleRow, type NotebookRow } from "@/lib/api"; +import { fetchPreview, getWorkspace, newNotebook, openNotebook, postViewport, type ModuleRow, type NotebookRow } from "@/lib/api"; import { parsePreview } from "@/lib/preview"; import { EnvelopeSocket, type Envelope } from "@/lib/envelope"; import { useRunLog } from "@/lib/runlog"; @@ -118,12 +118,14 @@ export function App() { socket.on("hello", (envelope) => { setNotebook((envelope["notebook"] as string) ?? null); setCurrentPath((envelope["path"] as string) ?? null); + // an empty workspace: the way forward is the workspace tab's "new" + if (!envelope["notebook"]) setLeftTab("workspace"); setKernelAlive(Boolean(envelope["kernel"])); // No notebook: nothing to wait for. Else the model is on its way. if (hasModel.current) return; const stage = envelope["notebook"] ? (envelope["kernel"] ? "building the model" : "starting the kernel") : null; setLoading(stage); - if (stage) setStatus(`${stage[0].toUpperCase()}${stage.slice(1)}…`); + setStatus(stage ? `${stage[0].toUpperCase()}${stage.slice(1)}…` : "No notebook yet: create one in the workspace tab"); setMarimoUrl((envelope["marimo_url"] as string) ?? null); refreshWorkspace(); }); @@ -312,6 +314,13 @@ export function App() { }); }; + const handleCreate = async (name: string, kind: "part" | "assembly") => { + setStatus(`creating ${name}…`); + await newNotebook(name, kind); + // the server opens it: show its cells + setLeftTab("notebook"); + }; + return (
No SimpleCAD notebooks in this workspace.
; - } + const [adding, setAdding] = useState(false); + const empty = notebooks.length === 0; return (notebooks
+