geop_core_editor/editor/protocol.rs
1//! What an [`super::Editor`] is told ([`Command`]) and what it answers
2//! ([`Update`]): the protocol every front end speaks, as JSON.
3
4use std::{collections::BTreeMap, rc::Rc};
5
6use geop_core_math::geop_error::{GeopError, GeopResult};
7use geop_core_program::{
8 element::PickedElement,
9 program::{Program, ProgramStep},
10};
11use serde::{Deserialize, Serialize};
12
13use crate::{
14 editable::Listed,
15 editing::{Presentation, StepEditEvent},
16 keys::AppKey,
17 output::{Export, ExporterInfo, Inspection, InspectorInfo},
18 registry::{Panel, StructureItem},
19 tools::ToolInfo,
20 view::{FaceMesh, PartView, ViewInstance, lit::Lighting},
21};
22
23/// Something the user did.
24#[derive(Clone, Debug, Deserialize)]
25#[serde(tag = "command", rename_all = "snake_case")]
26pub enum Command {
27 /// Nothing: only what to show, all of it — how an editor starts.
28 Show,
29 /// Start a new step of the operation `kind`, where the program runs to.
30 New {
31 kind: String,
32 },
33 /// Start a new step of the operation `kind` after the steps of the
34 /// part placed at `placed` — `neck`, or `neck/head` for one placed in a
35 /// placed part, however deep — edited where it is placed: built against
36 /// the parts placed beside it, which it reads in context (see
37 /// [`geop_core_program::placed::OUTSIDE`]). Committed, it is written to
38 /// that part's file.
39 NewIn {
40 kind: String,
41 placed: String,
42 },
43 /// Start editing the step `id` — of the program, or, given `placed`,
44 /// of the part placed at that path, however deep, where it is placed (see
45 /// [`StepInfo::placed`]).
46 Open {
47 id: String,
48 #[serde(default)]
49 placed: Option<String>,
50 },
51 /// Something the user did to the step being edited — or, with none,
52 /// with the tool in hand.
53 Event {
54 event: StepEditEvent,
55 },
56 /// Put the step being edited into the program — refused, unless it
57 /// builds.
58 Commit,
59 /// Stop editing the step, leaving the program as it was.
60 Cancel,
61 /// Whether the step being edited is shown as it builds, or the part
62 /// before it.
63 Preview {
64 preview: bool,
65 },
66 Remove {
67 id: String,
68 },
69 /// Move the step `id` to `index` among the other steps.
70 Move {
71 id: String,
72 index: usize,
73 },
74 /// The step `id` as text to paste ([`Program::excerpt`]), in the
75 /// update's export.
76 Copy {
77 id: String,
78 },
79 /// Insert the steps of the program `text` — what [`Command::Copy`]
80 /// gave, in this program or another — where new steps go
81 /// ([`Program::paste`]).
82 Paste {
83 text: String,
84 },
85 /// Run only the first `marker` steps — all of them, if `None` — and put
86 /// new steps there.
87 Seek {
88 marker: Option<usize>,
89 },
90 /// Replace the program, e.g. with one read from a file — `path`, if
91 /// given, which the files it places are named relative to.
92 Load {
93 program: Program,
94 #[serde(default)]
95 path: Option<String>,
96 },
97 /// The other program files are now these, by path: each set to its
98 /// program's text, or — `None` — gone. What the program places from
99 /// them is built anew.
100 Files {
101 files: BTreeMap<String, Option<String>>,
102 },
103 /// Load the example program `name` (see
104 /// [`crate::registry::ExampleSet`]).
105 LoadExample {
106 name: String,
107 },
108 /// Add the files of the example of several files `name` — put in
109 /// `folder`, if given — replacing any of the same path, and edit the
110 /// first of them. The update says what they are ([`Update::files`]):
111 /// the front end keeps them.
112 LoadWorkspaceExample {
113 name: String,
114 #[serde(default)]
115 folder: Option<String>,
116 },
117 /// Go back one edit — while a step is edited, one edit of the step —
118 /// or forward again.
119 Undo,
120 Redo,
121 /// Something the user did in the panel `key` (see
122 /// [`crate::registry::Panel`]), which the panel reads `payload` as.
123 Panel {
124 key: String,
125 payload: serde_json::Value,
126 },
127 /// Show the datum, sketch, solid or placed part `name` of the part
128 /// drawn, or hide it — whatever the editor would do by itself: a
129 /// display setting, saved with the program
130 /// ([`geop_core_program::program::Display`]), not a step.
131 Visibility {
132 name: String,
133 visible: bool,
134 },
135 /// Draw the placed part `name` — `bolt`, `asm/bolt` — in the colour
136 /// `color`, `#rrggbb`, over its own, or — `None` — in its own again:
137 /// a display setting, saved with the program, not a step.
138 Appearance {
139 name: String,
140 #[serde(default)]
141 color: Option<String>,
142 },
143 /// Show only the placed parts `names` — with the parts placed in them
144 /// and those they are placed in — of the parts placed, or every one
145 /// again for none: a display setting, saved with the program.
146 Isolate {
147 names: Vec<String>,
148 },
149 /// Take the tool `key` in hand (see [`crate::tools::Tool`]), or —
150 /// `None` — put the one in hand down. With no step being edited, the
151 /// events of the viewport are the tool's. `pick:<inspector>` is the
152 /// pick tool of an inspector that picks (see
153 /// [`crate::tools::pick::PickTool`]): every update carries its answer
154 /// about the picks ([`Update::inspection`]).
155 Tool {
156 key: Option<String>,
157 },
158 /// Ask the inspector `inspector` about the part as drawn — of the
159 /// elements `picked`, for one that picks — told `options` (its own,
160 /// see [`crate::output::Inspector::Options`]): answered once, in
161 /// [`Update::inspection`]. Changes nothing.
162 Inspect {
163 inspector: String,
164 #[serde(default)]
165 options: serde_json::Value,
166 #[serde(default)]
167 picked: Vec<PickedElement>,
168 },
169 /// Write what the program builds — as far as it runs, the parts it
170 /// places included — with the exporter `exporter`, in `format` (its
171 /// first, if not given), told `options` (its own, see
172 /// [`crate::output::Exporter::Options`]) and dated `date`
173 /// (`YYYY-MM-DD`): the update's [`Update::export`]. Changes nothing.
174 Export {
175 exporter: String,
176 #[serde(default)]
177 format: Option<String>,
178 #[serde(default)]
179 options: serde_json::Value,
180 #[serde(default)]
181 date: String,
182 },
183 /// Light `elements` too, beside what the step or the tool lights — what
184 /// an item of the structure or a row of an answer points at, while the
185 /// pointer is on it — until lit otherwise: none, once it leaves.
186 /// Changes nothing else (see [`Update::lit`]).
187 Light {
188 elements: Vec<PickedElement>,
189 },
190 /// What a bug report attaches of the session: the program, the step
191 /// being edited as it stands and the kernel's version, in the update's
192 /// [`Update::report`]. Changes nothing.
193 Report,
194 /// Panic, on purpose: how the front ends' recovery from a kernel that
195 /// crashed is checked (`web/e2e/`). A panic anywhere else is a bug;
196 /// this one stands in for it.
197 Crash,
198}
199
200impl Command {
201 /// The command sending the panel `P` its command `command`: what a
202 /// front end in Rust sends.
203 pub fn panel<P: Panel>(command: &P::Command) -> GeopResult<Self>
204 where
205 P::Command: Serialize,
206 {
207 let payload = serde_json::to_value(command)
208 .map_err(|e| GeopError::new(format!("a command of the panel `{}`: {e}", P::KEY)))?;
209 Ok(Self::Panel {
210 key: P::KEY.to_string(),
211 payload,
212 })
213 }
214}
215
216/// A step of the program, as a list of steps shows it.
217#[derive(Clone, Debug, PartialEq, Serialize)]
218pub struct StepInfo {
219 pub id: String,
220 pub kind: &'static str,
221 pub label: &'static str,
222 /// Its fields in one line: `sketch=outline, distance=1.00`.
223 pub summary: String,
224 /// Why it failed, if it ran and did.
225 pub error: Option<String>,
226 /// Whether it runs: it is before where the program runs to.
227 pub runs: bool,
228 /// Whether it is suppressed: it ran, and found it was not to (see
229 /// [`geop_core_program::program::ProgramStep::active`]), so it built
230 /// nothing.
231 pub suppressed: bool,
232 /// Whether it is the step being edited.
233 pub editing: bool,
234 /// The parts it placed, each with its program's steps, to edit where
235 /// it is placed ([`Command::Open`] with `placed`).
236 pub placed: Vec<PlacedSteps>,
237}
238
239/// A part a step placed, as the program shows it: what it is placed as —
240/// its path from the program, `neck/head` for one placed in a placed part —
241/// from which file, and the steps of that file's program, each with the
242/// parts it places in turn.
243#[derive(Clone, Debug, PartialEq, Serialize)]
244pub struct PlacedSteps {
245 pub instance: String,
246 /// The file it is placed from, as the workspace names it.
247 pub file: String,
248 pub steps: Vec<StepInfo>,
249}
250
251/// The program, as shown.
252#[derive(Clone, Debug, Serialize)]
253pub struct ProgramState {
254 /// The program itself, to save.
255 pub program: Program,
256 /// The file it is in, once the editor has been told.
257 pub path: Option<String>,
258 pub steps: Vec<StepInfo>,
259 /// How many steps run: new steps go there.
260 pub marker: usize,
261 pub can_undo: bool,
262 pub can_redo: bool,
263 /// The key of the tool in hand, if one is ([`Command::Tool`]).
264 pub tool: Option<String>,
265 /// The tools to take in hand, offered beside the inspectors — none of
266 /// them is an operation; the pick tools are the inspectors'.
267 pub tools: Vec<ToolInfo>,
268 /// Every operation a step can be, as the toolbar offers them: group by
269 /// group, in [`crate::editable::OperationGroup`]'s order, and within a
270 /// group by [`crate::editable::OperationTier`], the most used first,
271 /// then in the order they were registered.
272 pub operations: Vec<Listed>,
273 /// What can be written of the part ([`Command::Export`]).
274 pub exporters: Vec<&'static ExporterInfo>,
275 /// What can be asked about it ([`Command::Inspect`]), or picked in it
276 /// to ask about (the tool `pick:<inspector>`).
277 pub inspectors: Vec<&'static InspectorInfo>,
278 /// The names of the example programs [`Command::LoadExample`] loads.
279 pub examples: Vec<&'static str>,
280 /// The names of the examples of several files
281 /// [`Command::LoadWorkspaceExample`] loads.
282 pub workspace_examples: Vec<&'static str>,
283 /// What each panel shows of the program, by its key (see
284 /// [`crate::registry::Panel`]).
285 pub panels: BTreeMap<String, serde_json::Value>,
286 /// What the part's structure says beside its items, by their names,
287 /// from what the panels show (see [`crate::registry::Panel::details`]):
288 /// how free a placed part is.
289 pub details: BTreeMap<String, String>,
290 /// The keys of what every front end offers besides the operations
291 /// (see [`crate::keys`]).
292 pub keys: &'static [AppKey],
293}
294
295/// What is drawn: a part, and which of its sketches and datums not to.
296///
297/// Its faces' triangles are sent by key, each mesh once (see
298/// [`SceneState::meshes`]).
299///
300/// The parts placed in it — however many, however deep — are sent as what
301/// changed since the last scene: a viewer keeps them by name, and the
302/// views of their components by key, each sent once. So moving one placed
303/// part sends where that one is, and placing a screw a hundred times sends
304/// what a screw looks like once.
305#[derive(Clone, Debug, Serialize)]
306pub struct SceneState {
307 /// The part, without the parts placed in it: those are `instances`.
308 pub part: Rc<PartView>,
309 /// The sketches and datums the steps shown have used: what was made
310 /// from them shows them now. None of a kind while it is being picked.
311 /// Not sent — `None` — where it is as the last scene sent it: a drag
312 /// moving one placed part does not send every name again.
313 pub hidden: Option<Vec<String>>,
314 /// The parts placed in the part drawn, however deep, that are new or
315 /// moved or drawn from another component since the last scene — every
316 /// one, if `all`.
317 pub instances: Vec<ViewInstance>,
318 /// Whether the scene is all there is: a viewer forgets any other placed
319 /// parts, and every component and mesh it kept.
320 pub all: bool,
321 /// The names of the placed parts drawn last time and gone now.
322 pub removed: Vec<String>,
323 /// The views of the components the placed parts are drawn from, by key
324 /// (see [`ViewInstance::component`]), that the viewer does not have:
325 /// each is sent once, and kept until it is `forgotten`.
326 pub components: BTreeMap<String, Rc<PartView>>,
327 /// The components the viewer forgets now: none of its placed parts has
328 /// used them for longest. One is sent again once a placed part uses it.
329 /// Those of a part that leaves the scene for a while are kept, so that
330 /// editing a step before a large part placed after it does not send
331 /// that part again when it shows again.
332 pub forgotten: Vec<String>,
333 /// The meshes of the faces drawn — of the part, and of the components
334 /// sent — that the viewer does not have, by key (see
335 /// [`crate::view::FaceMesh`]): a face is sent by the key of its mesh,
336 /// and each mesh once, kept until it is `forgotten_meshes`. So showing
337 /// a part again with other sketches, or with one face changed, sends
338 /// the faces of none, or of that one.
339 pub meshes: BTreeMap<String, Rc<FaceMesh>>,
340 /// The meshes the viewer forgets now: no face drawn has used them for
341 /// longest.
342 pub forgotten_meshes: Vec<String>,
343 /// What the part has beyond its faces, to list and show or hide (see
344 /// [`crate::registry::Drawer::structure`]). Not sent — `None` — where
345 /// it is as the last scene sent it.
346 pub structure: Option<Vec<StructureItem>>,
347}
348
349/// The step being edited, as shown.
350#[derive(Clone, Debug, Serialize)]
351pub struct StepState {
352 pub kind: &'static str,
353 pub label: &'static str,
354 pub doc: &'static str,
355 /// Its id — none yet, for a new step.
356 pub id: Option<String>,
357 pub presentation: Presentation,
358 /// What it still needs picked, by its fields' labels: until it has it,
359 /// it is not built, and there is no error to show.
360 pub missing: Vec<String>,
361 /// Why it does not build, once it has what it needs; only a step that
362 /// builds can be committed.
363 pub error: Option<String>,
364 pub preview: bool,
365 /// Whether one of its edits can be undone, or redone.
366 pub can_undo: bool,
367 pub can_redo: bool,
368}
369
370/// What a bug report attaches of an editor's session ([`Command::Report`]):
371/// what the user was doing, as the kernel has it, so that a report says
372/// it whether or not the step was committed.
373#[derive(Clone, Debug, Serialize)]
374pub struct Report {
375 /// The program, as committed: without the step being edited.
376 pub program: Program,
377 /// The step being edited, if one is.
378 pub step: Option<ReportedStep>,
379 /// The kernel's version. (Which commit it was built from the front
380 /// end says, built from the same one: told here, every commit would
381 /// build every crate again.)
382 pub version: &'static str,
383}
384
385/// The step being edited, as a bug report attaches it: what it is, its
386/// arguments as its edits leave them, and why it does not build, as its
387/// dialog shows it.
388#[derive(Clone, Debug, Serialize)]
389pub struct ReportedStep {
390 /// Its id — none yet, for a new step.
391 pub id: Option<String>,
392 /// Where it is, or goes, among the program's steps.
393 pub index: usize,
394 /// The part placed in the program it is a step of, edited where it is
395 /// placed (see [`Command::Open`]), if it is one.
396 pub placed: Option<String>,
397 /// Its operation and arguments.
398 pub step: ProgramStep,
399 /// What it still needs picked, by its fields' labels.
400 pub missing: Vec<String>,
401 /// Why it does not build, as the dialog says it.
402 pub error: Option<String>,
403 /// The key of the field the error stands beside, if it concerns one
404 /// (see `docs/ux.md`, "An error stands beside its cause").
405 pub concerning: Option<String>,
406}
407
408/// A program file, as a front end keeps it.
409#[derive(Clone, Debug, Serialize)]
410pub struct File {
411 pub path: String,
412 pub program: Program,
413}
414
415/// What an editor shows after a command. What did not change since the
416/// last update is left out.
417#[derive(Clone, Debug, Serialize)]
418pub struct Update {
419 /// Why the command was refused, if it was: then it changed nothing.
420 pub error: Option<String>,
421 pub program: Option<ProgramState>,
422 pub scene: Option<SceneState>,
423 /// The step being edited; `None` if there is none.
424 pub step: Option<StepState>,
425 /// The program files the command added, the one now edited first.
426 pub files: Option<Vec<File>>,
427 /// The program files besides the one edited the command changed — a
428 /// step of a placed part committed to its file — for the front end to
429 /// keep: none if it changed none.
430 pub written: Option<Vec<File>>,
431 /// The file [`Command::Export`] wrote, or [`Command::Copy`] copied.
432 pub export: Option<Export>,
433 /// What the tool in hand shows, while no step is edited: the drag
434 /// tool's part it would drag lit, and whether a press grabs it; the
435 /// pick tool's picks, and what the answer about them draws.
436 pub tool: Option<Presentation>,
437 /// The answer of the tool in hand about the part — the pick tool's
438 /// inspector's about its picks — or the answer to [`Command::Inspect`].
439 pub inspection: Option<Inspection>,
440 /// What to draw lit, of the part drawn and of its placed parts, when
441 /// it changed (see [`crate::view::lit::Lighting`]): what the step or
442 /// the tool lights and what [`Command::Light`] does. A viewer keeps it
443 /// until it is sent again.
444 pub lit: Option<Lighting>,
445 /// What [`Command::Report`] asked for.
446 pub report: Option<Report>,
447}