better docs on solids and sketches (#5428)

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix docs;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* parens

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* parens

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2025-02-19 19:48:27 -08:00
committed by GitHub
parent f35cd3ef26
commit 099c48cd63
20 changed files with 957 additions and 434 deletions

View File

@ -18,12 +18,12 @@ chamfer(data: ChamferData, solid: Solid, tag?: TagDeclarator) -> Solid
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`ChamferData`](/docs/kcl/types/ChamferData) | Data for chamfers. | Yes | | `data` | [`ChamferData`](/docs/kcl/types/ChamferData) | Data for chamfers. | Yes |
| `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes | | `solid` | [`Solid`](/docs/kcl/types/Solid) | A solid is a collection of extrude surfaces. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No |
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

View File

@ -18,12 +18,12 @@ fillet(data: FilletData, solid: Solid, tag?: TagDeclarator) -> Solid
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`FilletData`](/docs/kcl/types/FilletData) | Data for fillets. | Yes | | `data` | [`FilletData`](/docs/kcl/types/FilletData) | Data for fillets. | Yes |
| `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes | | `solid` | [`Solid`](/docs/kcl/types/Solid) | A solid is a collection of extrude surfaces. | Yes |
| `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No | | `tag` | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No |
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

View File

@ -18,11 +18,11 @@ helixRevolutions(data: HelixRevolutionsData, solid: Solid) -> Solid
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `data` | [`HelixRevolutionsData`](/docs/kcl/types/HelixRevolutionsData) | Data for helix revolutions. | Yes | | `data` | [`HelixRevolutionsData`](/docs/kcl/types/HelixRevolutionsData) | Data for helix revolutions. | Yes |
| `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes | | `solid` | [`Solid`](/docs/kcl/types/Solid) | A solid is a collection of extrude surfaces. | Yes |
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

View File

@ -18,11 +18,11 @@ hollow(thickness: number, solid: Solid) -> Solid
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `thickness` | `number` | | Yes | | `thickness` | `number` | | Yes |
| `solid` | [`Solid`](/docs/kcl/types/Solid) | An solid is a collection of extrude surfaces. | Yes | | `solid` | [`Solid`](/docs/kcl/types/Solid) | A solid is a collection of extrude surfaces. | Yes |
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

View File

@ -25,7 +25,7 @@ loft(sketches: [Sketch], v_degree: NonZeroU32, bez_approximate_rational: bool, b
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

View File

@ -24,7 +24,7 @@ revolve(data: RevolveData, sketch: Sketch) -> Solid
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ sweep(sketch: Sketch, path: SweepPath, sectional?: bool, tolerance?: number) ->
### Returns ### Returns
[`Solid`](/docs/kcl/types/Solid) - An solid is a collection of extrude surfaces. [`Solid`](/docs/kcl/types/Solid) - A solid is a collection of extrude surfaces.
### Examples ### Examples

View File

@ -33,6 +33,7 @@ layout: manual
---- ----
A unit of length.
**Type:** `object` **Type:** `object`
@ -140,6 +141,7 @@ layout: manual
---- ----
A unit of angle.
**Type:** `object` **Type:** `object`

View File

@ -6,6 +6,40 @@ layout: manual
A sketch is a collection of paths. A sketch is a collection of paths.
When you define a sketch to a variable like:
```kcl
mySketch = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
```
The `mySketch` variable will be an executed [`Sketch`](/docs/kcl/types/Sketch) object. Executed being past tense, because the engine has already executed the commands to create the sketch.
The previous sketch commands will never be executed again, in this case.
If you would like to encapsulate the commands to create the sketch any time you call it, you can use a function.
```kcl
fn createSketch() {
return startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
}
```
Now, every time you call `createSketch()`, the commands will be executed and a new sketch will be created.
When you assign the result of `createSketch()` to a variable (`mySketch = createSketch()`), you are assigning the executed sketch to that variable. Meaning that the sketch `mySketch` will not be executed again.
You can still execute _new_ commands on the sketch like `extrude`, `revolve`, `loft`, etc. and the sketch will be updated.
**Type:** `object` **Type:** `object`

View File

@ -14,6 +14,40 @@ A sketch or a group of sketches.
A sketch is a collection of paths. A sketch is a collection of paths.
When you define a sketch to a variable like:
```kcl
mySketch = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
```
The `mySketch` variable will be an executed [`Sketch`](/docs/kcl/types/Sketch) object. Executed being past tense, because the engine has already executed the commands to create the sketch.
The previous sketch commands will never be executed again, in this case.
If you would like to encapsulate the commands to create the sketch any time you call it, you can use a function.
```kcl
fn createSketch() {
return startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
}
```
Now, every time you call `createSketch()`, the commands will be executed and a new sketch will be created.
When you assign the result of `createSketch()` to a variable (`mySketch = createSketch()`), you are assigning the executed sketch to that variable. Meaning that the sketch `mySketch` will not be executed again.
You can still execute _new_ commands on the sketch like `extrude`, `revolve`, `loft`, etc. and the sketch will be updated.
**Type:** `object` **Type:** `object`

View File

@ -1,10 +1,46 @@
--- ---
title: "Solid" title: "Solid"
excerpt: "An solid is a collection of extrude surfaces." excerpt: "A solid is a collection of extrude surfaces."
layout: manual layout: manual
--- ---
An solid is a collection of extrude surfaces. A solid is a collection of extrude surfaces.
When you define a solid to a variable like:
```kcl
myPart = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
```
The `myPart` variable will be an executed [`Solid`](/docs/kcl/types/Solid) object. Executed being past tense, because the engine has already executed the commands to create the solid.
The previous solid commands will never be executed again, in this case.
If you would like to encapsulate the commands to create the solid any time you call it, you can use a function.
```kcl
fn createPart() {
return startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
}
```
Now, every time you call `createPart()`, the commands will be executed and a new solid will be created.
When you assign the result of `createPart()` to a variable (`myPart = createPart()`), you are assigning the executed solid to that variable. Meaning that the solid `myPart` will not be executed again.
You can still execute _new_ commands on the solid like `shell`, `fillet`, `chamfer`, etc. and the solid will be updated.
**Type:** `object` **Type:** `object`
@ -24,7 +60,7 @@ An solid is a collection of extrude surfaces.
| `startCapId` |`string`| The id of the extrusion start cap | No | | `startCapId` |`string`| The id of the extrusion start cap | No |
| `endCapId` |`string`| The id of the extrusion end cap | No | | `endCapId` |`string`| The id of the extrusion end cap | No |
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No | | `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| An solid is a collection of extrude surfaces. | No | | `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A solid is a collection of extrude surfaces. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |

View File

@ -12,7 +12,43 @@ A solid or a group of solids.
**This schema accepts exactly one of the following:** **This schema accepts exactly one of the following:**
An solid is a collection of extrude surfaces. A solid is a collection of extrude surfaces.
When you define a solid to a variable like:
```kcl
myPart = startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
```
The `myPart` variable will be an executed [`Solid`](/docs/kcl/types/Solid) object. Executed being past tense, because the engine has already executed the commands to create the solid.
The previous solid commands will never be executed again, in this case.
If you would like to encapsulate the commands to create the solid any time you call it, you can use a function.
```kcl
fn createPart() {
return startSketchOn('XY')
|> startProfileAt([-12, 12], %)
|> line(end = [24, 0])
|> line(end = [0, -24])
|> line(end = [-24, 0])
|> close()
|> extrude(length = 6)
}
```
Now, every time you call `createPart()`, the commands will be executed and a new solid will be created.
When you assign the result of `createPart()` to a variable (`myPart = createPart()`), you are assigning the executed solid to that variable. Meaning that the solid `myPart` will not be executed again.
You can still execute _new_ commands on the solid like `shell`, `fillet`, `chamfer`, etc. and the solid will be updated.
**Type:** `object` **Type:** `object`

View File

@ -1,9 +1,10 @@
--- ---
title: "UnitAngle" title: "UnitAngle"
excerpt: "" excerpt: "A unit of angle."
layout: manual layout: manual
--- ---
A unit of angle.

View File

@ -1,9 +1,10 @@
--- ---
title: "UnitLen" title: "UnitLen"
excerpt: "" excerpt: "A unit of length."
layout: manual layout: manual
--- ---
A unit of length.

View File

@ -95,6 +95,28 @@ fn init_handlebars() -> Result<handlebars::Handlebars<'static>> {
), ),
); );
hbs.register_helper(
"firstLine",
Box::new(
|h: &handlebars::Helper,
_: &handlebars::Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext,
out: &mut dyn handlebars::Output|
-> handlebars::HelperResult {
// Get the first parameter passed to the helper
let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
// Get the first line using lines() iterator
let first = param.lines().next().unwrap_or("");
// Write the result
out.write(first)?;
Ok(())
},
),
);
hbs.register_helper( hbs.register_helper(
"neq", "neq",
Box::new( Box::new(
@ -566,6 +588,10 @@ fn generate_type(
})); }));
} }
// Cleanup the description.
let object = cleanup_type_description(&object)
.map_err(|e| anyhow::anyhow!("Failed to cleanup type description for type `{}`: {}", name, e))?;
let data = json!(schemars::schema::Schema::Object(object)); let data = json!(schemars::schema::Schema::Object(object));
let mut output = hbs.render("type", &data)?; let mut output = hbs.render("type", &data)?;
@ -576,6 +602,39 @@ fn generate_type(
Ok(()) Ok(())
} }
fn cleanup_type_description(object: &schemars::schema::SchemaObject) -> Result<schemars::schema::SchemaObject> {
let mut object = object.clone();
if let Some(metadata) = object.metadata.as_mut() {
if let Some(description) = metadata.description.as_mut() {
// Find any ```kcl code blocks and format the code.
// Parse any code blocks from the doc string.
let mut code_blocks = Vec::new();
let d = description.clone();
for line in d.lines() {
if line.starts_with("```kcl") && line.ends_with("```") {
code_blocks.push(line);
}
}
// Parse the kcl and recast it.
for code_block in &code_blocks {
let trimmed = code_block.trim_start_matches("```kcl").trim_end_matches("```");
let program = crate::Program::parse_no_errs(trimmed)?;
let options = crate::parsing::ast::types::FormatOptions {
insert_final_newline: false,
..Default::default()
};
let cleaned = program.ast.recast(&options, 0);
*description = description.replace(code_block, &format!("```kcl\n{}\n```", cleaned));
}
}
}
Ok(object)
}
fn clean_function_name(name: &str) -> String { fn clean_function_name(name: &str) -> String {
// Convert from camel case to snake case. // Convert from camel case to snake case.
let mut fn_name = name.to_case(convert_case::Case::Snake); let mut fn_name = name.to_case(convert_case::Case::Snake);
@ -733,6 +792,9 @@ fn recurse_and_create_references(
} }
} }
let obj = cleanup_type_description(&obj)
.map_err(|e| anyhow::anyhow!("Failed to cleanup type description for type `{}`: {}", name, e))?;
Ok(schemars::schema::Schema::Object(obj.clone())) Ok(schemars::schema::Schema::Object(obj.clone()))
} }

View File

@ -31,14 +31,14 @@ layout: manual
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
{{#each args}} {{#each args}}
| `{{name}}` | `{{type_}}` | {{{description}}} | {{#if required}}Yes{{else}}No{{/if}} | | `{{name}}` | `{{type_}}` | {{{firstLine description}}} | {{#if required}}Yes{{else}}No{{/if}} |
{{/each}} {{/each}}
{{/if}} {{/if}}
{{#if return_value}} {{#if return_value}}
### Returns ### Returns
`{{return_value.type_}}` {{#if return_value.description}}- {{{return_value.description}}}{{/if}} `{{return_value.type_}}` {{#if return_value.description}}- {{{firstLine return_value.description}}}{{/if}}
{{/if}} {{/if}}

View File

@ -8,6 +8,6 @@
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
{{#each properties}} {{#each properties}}
| `{{@key}}` | {{~ > propertyType this ~}} | {{{this.description}}} | {{#if (lookup ../required @key)}}Yes{{else}}No{{/if}} | | `{{@key}}` | {{~ > propertyType this ~}} | {{{firstLine this.description}}} | {{#if (lookup ../required @key)}}Yes{{else}}No{{/if}} |
{{/each}} {{/each}}
{{/if}} {{/if}}

View File

@ -408,6 +408,46 @@ pub enum PlaneType {
} }
/// A sketch is a collection of paths. /// A sketch is a collection of paths.
///
/// When you define a sketch to a variable like:
///
/// ```kcl
/// mySketch = startSketchOn('XY')
/// |> startProfileAt([-12, 12], %)
/// |> line(end = [24, 0])
/// |> line(end = [0, -24])
/// |> line(end = [-24, 0])
/// |> close()
/// ```
///
/// The `mySketch` variable will be an executed `Sketch` object. Executed being past
/// tense, because the engine has already executed the commands to create the sketch.
///
/// The previous sketch commands will never be executed again, in this case.
///
/// If you would like to encapsulate the commands to create the sketch any time you call it,
/// you can use a function.
///
/// ```kcl
/// fn createSketch() {
/// return startSketchOn('XY')
/// |> startProfileAt([-12, 12], %)
/// |> line(end = [24, 0])
/// |> line(end = [0, -24])
/// |> line(end = [-24, 0])
/// |> close()
/// }
/// ```
///
/// Now, every time you call `createSketch()`, the commands will be
/// executed and a new sketch will be created.
///
/// When you assign the result of `createSketch()` to a variable (`mySketch = createSketch()`), you are assigning
/// the executed sketch to that variable. Meaning that the sketch `mySketch` will not be executed
/// again.
///
/// You can still execute _new_ commands on the sketch like `extrude`, `revolve`, `loft`, etc. and
/// the sketch will be updated.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]
@ -538,7 +578,49 @@ impl Sketch {
} }
} }
/// An solid is a collection of extrude surfaces. /// A solid is a collection of extrude surfaces.
///
/// When you define a solid to a variable like:
///
/// ```kcl
/// myPart = startSketchOn('XY')
/// |> startProfileAt([-12, 12], %)
/// |> line(end = [24, 0])
/// |> line(end = [0, -24])
/// |> line(end = [-24, 0])
/// |> close()
/// |> extrude(length = 6)
/// ```
///
/// The `myPart` variable will be an executed `Solid` object. Executed being past
/// tense, because the engine has already executed the commands to create the solid.
///
/// The previous solid commands will never be executed again, in this case.
///
/// If you would like to encapsulate the commands to create the solid any time you call it,
/// you can use a function.
///
/// ```kcl
/// fn createPart() {
/// return startSketchOn('XY')
/// |> startProfileAt([-12, 12], %)
/// |> line(end = [24, 0])
/// |> line(end = [0, -24])
/// |> line(end = [-24, 0])
/// |> close()
/// |> extrude(length = 6)
/// }
/// ```
///
/// Now, every time you call `createPart()`, the commands will be
/// executed and a new solid will be created.
///
/// When you assign the result of `createPart()` to a variable (`myPart = createPart()`), you are assigning
/// the executed solid to that variable. Meaning that the solid `myPart` will not be executed
/// again.
///
/// You can still execute _new_ commands on the solid like `shell`, `fillet`, `chamfer`, etc.
/// and the solid will be updated.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]

View File

@ -730,6 +730,7 @@ pub enum UnitType {
} }
// TODO called UnitLen so as not to clash with UnitLength in settings) // TODO called UnitLen so as not to clash with UnitLength in settings)
/// A unit of length.
#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)] #[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]
@ -811,6 +812,7 @@ impl From<UnitLen> for kittycad_modeling_cmds::units::UnitLength {
} }
} }
/// A unit of angle.
#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)] #[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type")] #[serde(tag = "type")]