Skip to main content

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}