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:
@ -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(
|
||||
"neq",
|
||||
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 mut output = hbs.render("type", &data)?;
|
||||
@ -576,6 +602,39 @@ fn generate_type(
|
||||
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 {
|
||||
// Convert from camel case to snake case.
|
||||
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()))
|
||||
}
|
||||
|
||||
|
@ -31,14 +31,14 @@ layout: manual
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
{{#each args}}
|
||||
| `{{name}}` | `{{type_}}` | {{{description}}} | {{#if required}}Yes{{else}}No{{/if}} |
|
||||
| `{{name}}` | `{{type_}}` | {{{firstLine description}}} | {{#if required}}Yes{{else}}No{{/if}} |
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if return_value}}
|
||||
### 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}}
|
||||
|
||||
|
@ -8,6 +8,6 @@
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
{{#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}}
|
||||
{{/if}}
|
||||
|
@ -408,6 +408,46 @@ pub enum PlaneType {
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
#[ts(export)]
|
||||
#[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)]
|
||||
#[ts(export)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
|
@ -730,6 +730,7 @@ pub enum UnitType {
|
||||
}
|
||||
|
||||
// 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)]
|
||||
#[ts(export)]
|
||||
#[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)]
|
||||
#[ts(export)]
|
||||
#[serde(tag = "type")]
|
||||
|
Reference in New Issue
Block a user