KCL: Customizable per-arg and per-fn snippet values (#7156)
Before, the LSP snippet for `startProfile` was
```
startProfile(%, at = [3.14, 3.14])
```
Now it's
```
startProfile(%, at = [0, 0])
```
This is configured by adding a `snippet_value=` field to the stdlib macro. For example:
```diff
#[stdlib {
name = "startProfile",
keywords = true,
unlabeled_first = true,
args = {
sketch_surface = { docs = "What to start the profile on" },
- at = { docs = "Where to start the profile. An absolute point." },
+ at = { docs = "Where to start the profile. An absolute point.", snippet_value = "[0, 0]" }, tag = { docs = "Tag this first starting point" },
},
tags = ["sketch"]
}]
```
## Work for follow-up PRs
- Make this work for KCL functions defined in KCL, e.g. [`fn circle`](36c8ad439d/rust/kcl-lib/std/sketch.kcl (L31-L32)
) -- something like `@(snippet_value = "[0, 0]")` perhaps
- Go through the stdlib and change defaults where appropriate
This commit is contained in:
@ -207425,6 +207425,10 @@
|
|||||||
},
|
},
|
||||||
"required": true,
|
"required": true,
|
||||||
"includeInSnippet": true,
|
"includeInSnippet": true,
|
||||||
|
"snippetValueArray": [
|
||||||
|
"0",
|
||||||
|
"0"
|
||||||
|
],
|
||||||
"description": "Where to start the profile. An absolute point.",
|
"description": "Where to start the profile. An absolute point.",
|
||||||
"labelRequired": true
|
"labelRequired": true
|
||||||
},
|
},
|
||||||
|
@ -1001,7 +1001,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|
|||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`@settings(defaultLengthUnit = in)
|
`@settings(defaultLengthUnit = in)
|
||||||
sketch001 = startSketchOn(XZ)
|
sketch001 = startSketchOn(XZ)
|
||||||
|> startProfile(%, at = [3.14, 12])
|
|> startProfile(%, at = [0, 12])
|
||||||
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
|
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1076,7 +1076,7 @@ sketch001 = startSketchOn(XZ)
|
|||||||
await expect(page.locator('.cm-content')).toHaveText(
|
await expect(page.locator('.cm-content')).toHaveText(
|
||||||
`@settings(defaultLengthUnit = in)
|
`@settings(defaultLengthUnit = in)
|
||||||
sketch001 = startSketchOn(XZ)
|
sketch001 = startSketchOn(XZ)
|
||||||
|> startProfile(%, at = [3.14, 12])
|
|> startProfile(%, at = [0, 12])
|
||||||
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
|
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -47,6 +47,14 @@ struct ArgMetadata {
|
|||||||
/// Does not do anything if the argument is already required.
|
/// Does not do anything if the argument is already required.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
include_in_snippet: bool,
|
include_in_snippet: bool,
|
||||||
|
|
||||||
|
/// The snippet should suggest this value for the arg.
|
||||||
|
#[serde(default)]
|
||||||
|
snippet_value: Option<String>,
|
||||||
|
|
||||||
|
/// The snippet should suggest this value for the arg.
|
||||||
|
#[serde(default)]
|
||||||
|
snippet_value_array: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
@ -318,6 +326,10 @@ fn do_stdlib_inner(
|
|||||||
}
|
}
|
||||||
.trim_start_matches('_')
|
.trim_start_matches('_')
|
||||||
.to_string();
|
.to_string();
|
||||||
|
// These aren't really KCL args, they're just state that each stdlib function's impl needs.
|
||||||
|
if arg_name == "exec_state" || arg_name == "args" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let ty = match arg {
|
let ty = match arg {
|
||||||
syn::FnArg::Receiver(pat) => pat.ty.as_ref().into_token_stream(),
|
syn::FnArg::Receiver(pat) => pat.ty.as_ref().into_token_stream(),
|
||||||
@ -328,27 +340,24 @@ fn do_stdlib_inner(
|
|||||||
|
|
||||||
let ty_string = rust_type_to_openapi_type(&ty_string);
|
let ty_string = rust_type_to_openapi_type(&ty_string);
|
||||||
let required = !ty_ident.to_string().starts_with("Option <");
|
let required = !ty_ident.to_string().starts_with("Option <");
|
||||||
let arg_meta = metadata.args.get(&arg_name);
|
let Some(arg_meta) = metadata.args.get(&arg_name) else {
|
||||||
let description = if let Some(s) = arg_meta.map(|arg| &arg.docs) {
|
errors.push(Error::new_spanned(arg, format!("arg {arg_name} not found")));
|
||||||
quote! { #s }
|
|
||||||
} else if metadata.keywords && ty_string != "Args" && ty_string != "ExecState" {
|
|
||||||
errors.push(Error::new_spanned(
|
|
||||||
&arg,
|
|
||||||
"Argument was not documented in the args block",
|
|
||||||
));
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
quote! { String::new() }
|
|
||||||
};
|
};
|
||||||
let include_in_snippet = required || arg_meta.map(|arg| arg.include_in_snippet).unwrap_or_default();
|
let description = arg_meta.docs.clone();
|
||||||
|
let include_in_snippet = required || arg_meta.include_in_snippet;
|
||||||
|
let snippet_value = arg_meta.snippet_value.clone();
|
||||||
|
let snippet_value_array = arg_meta.snippet_value_array.clone();
|
||||||
|
if snippet_value.is_some() && snippet_value_array.is_some() {
|
||||||
|
errors.push(Error::new_spanned(arg, format!("arg {arg_name} has set both snippet_value and snippet_value array, but at most one of these may be set. Please delete one of them.")));
|
||||||
|
}
|
||||||
let label_required = !(i == 0 && metadata.unlabeled_first);
|
let label_required = !(i == 0 && metadata.unlabeled_first);
|
||||||
let camel_case_arg_name = to_camel_case(&arg_name);
|
let camel_case_arg_name = to_camel_case(&arg_name);
|
||||||
if ty_string != "ExecState" && ty_string != "Args" {
|
if ty_string != "ExecState" && ty_string != "Args" {
|
||||||
let schema = quote! {
|
let schema = quote! {
|
||||||
generator.root_schema_for::<#ty_ident>()
|
generator.root_schema_for::<#ty_ident>()
|
||||||
};
|
};
|
||||||
arg_types.push(quote! {
|
let q0 = quote! {
|
||||||
#docs_crate::StdLibFnArg {
|
|
||||||
name: #camel_case_arg_name.to_string(),
|
name: #camel_case_arg_name.to_string(),
|
||||||
type_: #ty_string.to_string(),
|
type_: #ty_string.to_string(),
|
||||||
schema: #schema,
|
schema: #schema,
|
||||||
@ -356,6 +365,32 @@ fn do_stdlib_inner(
|
|||||||
label_required: #label_required,
|
label_required: #label_required,
|
||||||
description: #description.to_string(),
|
description: #description.to_string(),
|
||||||
include_in_snippet: #include_in_snippet,
|
include_in_snippet: #include_in_snippet,
|
||||||
|
};
|
||||||
|
let q1 = if let Some(snippet_value) = snippet_value {
|
||||||
|
quote! {
|
||||||
|
snippet_value: Some(#snippet_value.to_owned()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
snippet_value: None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let q2 = if let Some(snippet_value_array) = snippet_value_array {
|
||||||
|
quote! {
|
||||||
|
snippet_value_array: Some(vec![
|
||||||
|
#(#snippet_value_array.to_owned()),*
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
snippet_value_array: None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
arg_types.push(quote! {
|
||||||
|
#docs_crate::StdLibFnArg {
|
||||||
|
#q0
|
||||||
|
#q1
|
||||||
|
#q2
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -419,6 +454,8 @@ fn do_stdlib_inner(
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,6 +40,9 @@ fn test_args_with_refs() {
|
|||||||
let (item, mut errors) = do_stdlib(
|
let (item, mut errors) = do_stdlib(
|
||||||
quote! {
|
quote! {
|
||||||
name = "someFn",
|
name = "someFn",
|
||||||
|
args = {
|
||||||
|
data = { docs = "The data for this function"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
quote! {
|
quote! {
|
||||||
/// Docs
|
/// Docs
|
||||||
@ -65,6 +68,9 @@ fn test_args_with_lifetime() {
|
|||||||
let (item, mut errors) = do_stdlib(
|
let (item, mut errors) = do_stdlib(
|
||||||
quote! {
|
quote! {
|
||||||
name = "someFn",
|
name = "someFn",
|
||||||
|
args = {
|
||||||
|
data = { docs = "Arg for the function" },
|
||||||
|
}
|
||||||
},
|
},
|
||||||
quote! {
|
quote! {
|
||||||
/// Docs
|
/// Docs
|
||||||
@ -117,7 +123,8 @@ fn test_stdlib_line_to() {
|
|||||||
quote! {
|
quote! {
|
||||||
name = "lineTo",
|
name = "lineTo",
|
||||||
args = {
|
args = {
|
||||||
sketch = { docs = "the sketch you're adding the line to" }
|
data = { docs = "the sketch you're adding the line to" },
|
||||||
|
sketch = { docs = "the sketch you're adding the line to" },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
quote! {
|
quote! {
|
||||||
|
@ -105,8 +105,10 @@ impl crate::docs::StdLibFn for SomeFn {
|
|||||||
schema: generator.root_schema_for::<Foo>(),
|
schema: generator.root_schema_for::<Foo>(),
|
||||||
required: true,
|
required: true,
|
||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new().to_string(),
|
description: "Arg for the function".to_string(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +125,8 @@ impl crate::docs::StdLibFn for SomeFn {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,8 +105,10 @@ impl crate::docs::StdLibFn for SomeFn {
|
|||||||
schema: generator.root_schema_for::<str>(),
|
schema: generator.root_schema_for::<str>(),
|
||||||
required: true,
|
required: true,
|
||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new().to_string(),
|
description: "The data for this function".to_string(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +125,8 @@ impl crate::docs::StdLibFn for SomeFn {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "[number]".to_string(),
|
|
||||||
schema: generator.root_schema_for::<[f64; 2usize]>(),
|
|
||||||
required: true,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: true,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "number".to_string(),
|
|
||||||
schema: generator.root_schema_for::<f64>(),
|
|
||||||
required: true,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: true,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,15 +101,7 @@ impl crate::docs::StdLibFn for MyFunc {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "kittycad::types::InputFormat".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
|
||||||
required: false,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: false,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -125,6 +117,8 @@ impl crate::docs::StdLibFn for MyFunc {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,8 +108,10 @@ impl crate::docs::StdLibFn for LineTo {
|
|||||||
schema: generator.root_schema_for::<LineToData>(),
|
schema: generator.root_schema_for::<LineToData>(),
|
||||||
required: true,
|
required: true,
|
||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new().to_string(),
|
description: "the sketch you're adding the line to".to_string(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
},
|
},
|
||||||
crate::docs::StdLibFnArg {
|
crate::docs::StdLibFnArg {
|
||||||
name: "sketch".to_string(),
|
name: "sketch".to_string(),
|
||||||
@ -119,6 +121,8 @@ impl crate::docs::StdLibFn for LineTo {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: "the sketch you're adding the line to".to_string(),
|
description: "the sketch you're adding the line to".to_string(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -136,6 +140,8 @@ impl crate::docs::StdLibFn for LineTo {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Min {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "[number]".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Vec<f64>>(),
|
|
||||||
required: true,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: true,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Min {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "number".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Option<f64>>(),
|
|
||||||
required: false,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: false,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "kittycad::types::InputFormat".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
|
||||||
required: false,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: false,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "kittycad::types::InputFormat".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
|
||||||
required: false,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: false,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "kittycad::types::InputFormat".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
|
||||||
required: false,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: false,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Import {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,15 +100,7 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||||
settings.inline_subschemas = inline_subschemas;
|
settings.inline_subschemas = inline_subschemas;
|
||||||
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
let mut generator = schemars::gen::SchemaGenerator::new(settings);
|
||||||
vec![crate::docs::StdLibFnArg {
|
vec![]
|
||||||
name: "args".to_string(),
|
|
||||||
type_: "[number]".to_string(),
|
|
||||||
schema: generator.root_schema_for::<Vec<f64>>(),
|
|
||||||
required: true,
|
|
||||||
label_required: true,
|
|
||||||
description: String::new().to_string(),
|
|
||||||
include_in_snippet: true,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
|
||||||
@ -124,6 +116,8 @@ impl crate::docs::StdLibFn for Show {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,8 @@ impl crate::docs::StdLibFn for SomeFunction {
|
|||||||
label_required: true,
|
label_required: true,
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
include_in_snippet: true,
|
include_in_snippet: true,
|
||||||
|
snippet_value: None,
|
||||||
|
snippet_value_array: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,13 @@ pub struct StdLibFnArg {
|
|||||||
/// Include this in completion snippets?
|
/// Include this in completion snippets?
|
||||||
#[serde(default, skip_serializing_if = "is_false")]
|
#[serde(default, skip_serializing_if = "is_false")]
|
||||||
pub include_in_snippet: bool,
|
pub include_in_snippet: bool,
|
||||||
|
/// Snippet should suggest this value for the argument.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub snippet_value: Option<String>,
|
||||||
|
/// Snippet should suggest this value for the argument.
|
||||||
|
/// The suggested value should be an array, with these elements.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub snippet_value_array: Option<Vec<String>>,
|
||||||
/// Additional information that could be used instead of the type's description.
|
/// Additional information that could be used instead of the type's description.
|
||||||
/// This is helpful if the type is really basic, like "u32" -- that won't tell the user much about
|
/// This is helpful if the type is really basic, like "u32" -- that won't tell the user much about
|
||||||
/// how this argument is meant to be used.
|
/// how this argument is meant to be used.
|
||||||
@ -165,6 +172,21 @@ impl StdLibFnArg {
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
if let Some(vals) = &self.snippet_value_array {
|
||||||
|
let mut snippet = label.to_owned();
|
||||||
|
snippet.push('[');
|
||||||
|
for (i, val) in vals.iter().enumerate() {
|
||||||
|
snippet.push_str(&format!("${{{}:{}}}", index + i, val));
|
||||||
|
if i != vals.len() - 1 {
|
||||||
|
snippet.push_str(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snippet.push(']');
|
||||||
|
return Ok(Some((index + vals.len(), snippet)));
|
||||||
|
}
|
||||||
|
if let Some(val) = &self.snippet_value {
|
||||||
|
return Ok(Some((index, format!("{label}${{{}:{}}}", index, val))));
|
||||||
|
}
|
||||||
if (self.type_ == "Sketch"
|
if (self.type_ == "Sketch"
|
||||||
|| self.type_ == "[Sketch]"
|
|| self.type_ == "[Sketch]"
|
||||||
|| self.type_ == "Geometry"
|
|| self.type_ == "Geometry"
|
||||||
@ -988,6 +1010,13 @@ mod tests {
|
|||||||
assert_eq!(snippet, r#"startSketchOn(${0:XY})"#);
|
assert_eq!(snippet, r#"startSketchOn(${0:XY})"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_autocomplete_snippet_start_profile() {
|
||||||
|
let start_sketch_on_fn: Box<dyn StdLibFn> = Box::new(crate::std::sketch::StartProfile);
|
||||||
|
let snippet = start_sketch_on_fn.to_autocomplete_snippet().unwrap();
|
||||||
|
assert_eq!(snippet, r#"startProfile(${0:%}, at = [${1:0}, ${2:0}])"#);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_autocomplete_snippet_pattern_circular_3d() {
|
fn get_autocomplete_snippet_pattern_circular_3d() {
|
||||||
// We test this one specifically because it has ints and floats and strings.
|
// We test this one specifically because it has ints and floats and strings.
|
||||||
|
@ -1322,7 +1322,7 @@ pub async fn start_profile(exec_state: &mut ExecState, args: Args) -> Result<Kcl
|
|||||||
unlabeled_first = true,
|
unlabeled_first = true,
|
||||||
args = {
|
args = {
|
||||||
sketch_surface = { docs = "What to start the profile on" },
|
sketch_surface = { docs = "What to start the profile on" },
|
||||||
at = { docs = "Where to start the profile. An absolute point." },
|
at = { docs = "Where to start the profile. An absolute point.", snippet_value_array = ["0", "0"] },
|
||||||
tag = { docs = "Tag this first starting point" },
|
tag = { docs = "Tag this first starting point" },
|
||||||
},
|
},
|
||||||
tags = ["sketch"]
|
tags = ["sketch"]
|
||||||
|
Reference in New Issue
Block a user