kcl_api/
lib.rs

1//! An API for controlling the KCL interpreter from the frontend.
2
3#![allow(async_fn_in_trait)]
4
5use kcl_error::SourceRange;
6use serde::{Deserialize, Serialize};
7
8pub mod sketch;
9
10pub trait LifecycleApi {
11    async fn open_project(&self, project: ProjectId, files: Vec<File>, open_file: FileId) -> Result<()>;
12    async fn add_file(&self, project: ProjectId, file: File) -> Result<()>;
13    async fn remove_file(&self, project: ProjectId, file: FileId) -> Result<()>;
14    // File changed on disk, etc. outside of the editor or applying undo, restore, etc.
15    async fn update_file(&self, project: ProjectId, file: FileId, text: String) -> Result<()>;
16    async fn switch_file(&self, project: ProjectId, file: FileId) -> Result<()>;
17    async fn refresh(&self, project: ProjectId) -> Result<()>;
18}
19
20#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
21#[ts(export)]
22pub struct SceneGraph {
23    pub project: ProjectId,
24    pub file: FileId,
25    pub version: Version,
26
27    pub objects: Vec<Object>,
28    pub settings: Settings,
29    pub sketch_mode: Option<ObjectId>,
30}
31
32impl SceneGraph {
33    pub fn empty(project: ProjectId, file: FileId, version: Version) -> Self {
34        SceneGraph {
35            project,
36            file,
37            version,
38            objects: Vec::new(),
39            settings: Settings {},
40            sketch_mode: None,
41        }
42    }
43}
44
45#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
46#[ts(export)]
47pub struct SceneGraphDelta {
48    pub new_graph: SceneGraph,
49    pub new_objects: Vec<ObjectId>,
50    pub invalidates_ids: bool,
51}
52
53impl SceneGraphDelta {
54    pub fn new(new_graph: SceneGraph, new_objects: Vec<ObjectId>, invalidates_ids: bool) -> Self {
55        SceneGraphDelta {
56            new_graph,
57            new_objects,
58            invalidates_ids,
59        }
60    }
61}
62
63#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
64#[ts(export)]
65pub struct SourceDelta {}
66
67#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, ts_rs::TS)]
68#[ts(export, rename = "ApiObjectId")]
69pub struct ObjectId(pub usize);
70
71#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ts_rs::TS)]
72#[ts(export, rename = "ApiVersion")]
73pub struct Version(pub usize);
74
75#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, ts_rs::TS)]
76#[ts(export, rename = "ApiProjectId")]
77pub struct ProjectId(pub usize);
78
79#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Deserialize, Serialize, ts_rs::TS)]
80#[ts(export, rename = "ApiFileId")]
81pub struct FileId(pub usize);
82
83#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
84#[ts(export, rename = "ApiFile")]
85pub struct File {
86    pub id: FileId,
87    pub path: String,
88    pub text: String,
89}
90
91#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
92#[ts(export, rename = "ApiSettings")]
93pub struct Settings {}
94
95#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
96pub struct Object {
97    pub id: ObjectId,
98    pub kind: ObjectKind,
99    pub label: String,
100    pub comments: String,
101    pub artifact_id: usize,
102    pub source: SourceRef,
103}
104
105#[allow(clippy::large_enum_variant)]
106#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
107pub enum ObjectKind {
108    Sketch(crate::sketch::Sketch),
109    Segment(crate::sketch::Segment),
110    Constraint(crate::sketch::Constraint),
111    // TODO
112    Region,
113    Sweep,
114}
115
116#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
117pub enum Plane {
118    Object(ObjectId),
119    Default,
120}
121
122#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
123pub enum SourceRef {
124    Simple(SourceRange),
125    BackTrace(Vec<SourceRange>),
126}
127
128#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
129#[ts(export)]
130pub struct Number {
131    value: f64,
132    units: NumericSuffix,
133}
134
135#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
136#[ts(export)]
137pub enum Expr {
138    Number(Number),
139    Var(Number),
140    Variable(String),
141}
142
143// TODO share with kcl-lib
144#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, ts_rs::TS)]
145#[repr(u32)]
146#[ts(export)]
147pub enum NumericSuffix {
148    None,
149    Count,
150    Length,
151    Angle,
152    Mm,
153    Cm,
154    M,
155    Inch,
156    Ft,
157    Yd,
158    Deg,
159    Rad,
160    Unknown,
161}
162
163#[derive(Debug, Clone, Deserialize, Serialize, ts_rs::TS)]
164#[ts(export)]
165pub struct Error {
166    pub msg: String,
167}
168
169impl Error {
170    pub fn file_id_in_use(id: FileId, path: &str) -> Self {
171        Error {
172            msg: format!("File ID already in use: {id:?}, currently used for `{path}`"),
173        }
174    }
175
176    pub fn bad_project(found: ProjectId, expected: Option<ProjectId>) -> Self {
177        let msg = match expected {
178            Some(expected) => format!("Project ID mismatch found: {found:?}, expected: {expected:?}"),
179            None => format!("No open project, found: {found:?}"),
180        };
181        Error { msg }
182    }
183
184    pub fn bad_version(found: Version, expected: Version) -> Self {
185        Error {
186            msg: format!("Version mismatch found: {found:?}, expected: {expected:?}"),
187        }
188    }
189
190    pub fn bad_file(found: FileId, expected: Option<FileId>) -> Self {
191        let msg = match expected {
192            Some(expected) => format!("File ID mismatch found: {found:?}, expected: {expected:?}"),
193            None => format!("File ID not found: {found:?}"),
194        };
195        Error { msg }
196    }
197
198    pub fn serialize(e: impl serde::ser::Error) -> Self {
199        Error {
200            msg: format!(
201                "Could not serialize successful KCL result. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"
202            ),
203        }
204    }
205
206    pub fn deserialize(name: &str, e: impl serde::de::Error) -> Self {
207        Error {
208            msg: format!(
209                "Could not deserialize argument `{name}`. This is a bug in KCL and not in your code, please report this to Zoo. Details: {e}"
210            ),
211        }
212    }
213}
214
215pub type Result<T> = std::result::Result<T, Error>;