Compare commits
14 Commits
pierremtb/
...
franknoiro
| Author | SHA1 | Date | |
|---|---|---|---|
| c64c4705ef | |||
| a122128e0b | |||
| 0fe79ea7cb | |||
| 021e4b9565 | |||
| e57783483a | |||
| e952148cd2 | |||
| b5028f7aa8 | |||
| df6b4f4c37 | |||
| 41eb64925b | |||
| fc076173ff | |||
| 98822869f7 | |||
| df0510c199 | |||
| fda65bcbd7 | |||
| c37e564b59 |
21
.github/workflows/cargo-bench.yml
vendored
21
.github/workflows/cargo-bench.yml
vendored
@ -40,13 +40,16 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cargo install cargo-criterion
|
||||
sudo apt update
|
||||
sudo apt install -y valgrind
|
||||
- uses: boa-dev/criterion-compare-action@v3
|
||||
cargo install cargo-codspeed
|
||||
cd rust/kcl-lib
|
||||
cargo add --dev codspeed-criterion-compat --rename criterion
|
||||
- name: Build the benchmark target(s)
|
||||
run: |
|
||||
cd rust
|
||||
cargo codspeed build
|
||||
- name: Run the benchmarks
|
||||
uses: CodSpeedHQ/action@v3
|
||||
with:
|
||||
cwd: "rust"
|
||||
defaultFeatures: true
|
||||
# Needed. The name of the branch to compare with. This default uses the branch which is being pulled against
|
||||
branchName: ${{ github.base_ref }}
|
||||
env:
|
||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
|
||||
working-directory: rust
|
||||
run: KITTYCAD_API_TOKEN=${{secrets.KITTYCAD_API_TOKEN}} cargo codspeed run
|
||||
token: ${{ secrets.CODSPEED_TOKEN }}
|
||||
|
||||
4
.github/workflows/generate-website-docs.yml
vendored
4
.github/workflows/generate-website-docs.yml
vendored
@ -40,9 +40,13 @@ jobs:
|
||||
# cleanup old
|
||||
rm -rf documentation/content/pages/docs/kcl/*.md
|
||||
rm -rf documentation/content/pages/docs/kcl/types
|
||||
rm -rf documentation/content/pages/docs/kcl/settings
|
||||
rm -rf documentation/content/pages/docs/kcl/consts
|
||||
# move new
|
||||
mv -f docs/kcl/*.md documentation/content/pages/docs/kcl/
|
||||
mv -f docs/kcl/types documentation/content/pages/docs/kcl/
|
||||
mv -f docs/kcl/settings documentation/content/pages/docs/kcl/
|
||||
mv -f docs/kcl/consts documentation/content/pages/docs/kcl/
|
||||
- name: move kcl-samples
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
2
.github/workflows/kcl-python-bindings.yml
vendored
2
.github/workflows/kcl-python-bindings.yml
vendored
@ -161,6 +161,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: rust/kcl-python-bindings
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
- name: do uv things
|
||||
|
||||
25
docs/kcl/consts.md
Normal file
25
docs/kcl/consts.md
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
title: "KCL Constants"
|
||||
excerpt: "Documentation for the KCL constants."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
### `std`
|
||||
|
||||
- [`HALF_TURN`](/docs/kcl/consts/std-HALF_TURN)
|
||||
- [`QUARTER_TURN`](/docs/kcl/consts/std-QUARTER_TURN)
|
||||
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-THREE_QUARTER_TURN)
|
||||
- [`XY`](/docs/kcl/consts/std-XY)
|
||||
- [`XZ`](/docs/kcl/consts/std-XZ)
|
||||
- [`YZ`](/docs/kcl/consts/std-YZ)
|
||||
- [`ZERO`](/docs/kcl/consts/std-ZERO)
|
||||
|
||||
### `std::math`
|
||||
|
||||
- [`E`](/docs/kcl/consts/std-math-E)
|
||||
- [`PI`](/docs/kcl/consts/std-math-PI)
|
||||
- [`TAU`](/docs/kcl/consts/std-math-TAU)
|
||||
|
||||
@ -12,25 +12,26 @@ layout: manual
|
||||
* [`Modules`](kcl/modules)
|
||||
* [`Settings`](kcl/settings)
|
||||
* [`Known Issues`](kcl/known-issues)
|
||||
* [`Constants`](kcl/consts)
|
||||
|
||||
### Standard library
|
||||
|
||||
* **Primitive types**
|
||||
* [`bool`](kcl/bool)
|
||||
* [`number`](kcl/number)
|
||||
* [`string`](kcl/string)
|
||||
* [`tag`](kcl/tag)
|
||||
* [`bool`](kcl/types/bool)
|
||||
* [`number`](kcl/types/number)
|
||||
* [`string`](kcl/types/string)
|
||||
* [`tag`](kcl/types/tag)
|
||||
* **std**
|
||||
* [`HALF_TURN`](kcl/const_std-HALF_TURN)
|
||||
* [`Plane`](kcl/Plane)
|
||||
* [`QUARTER_TURN`](kcl/const_std-QUARTER_TURN)
|
||||
* [`Sketch`](kcl/Sketch)
|
||||
* [`Solid`](kcl/Solid)
|
||||
* [`THREE_QUARTER_TURN`](kcl/const_std-THREE_QUARTER_TURN)
|
||||
* [`XY`](kcl/const_std-XY)
|
||||
* [`XZ`](kcl/const_std-XZ)
|
||||
* [`YZ`](kcl/const_std-YZ)
|
||||
* [`ZERO`](kcl/const_std-ZERO)
|
||||
* [`HALF_TURN`](kcl/consts/std-HALF_TURN)
|
||||
* [`Plane`](kcl/types/Plane)
|
||||
* [`QUARTER_TURN`](kcl/consts/std-QUARTER_TURN)
|
||||
* [`Sketch`](kcl/types/Sketch)
|
||||
* [`Solid`](kcl/types/Solid)
|
||||
* [`THREE_QUARTER_TURN`](kcl/consts/std-THREE_QUARTER_TURN)
|
||||
* [`XY`](kcl/consts/std-XY)
|
||||
* [`XZ`](kcl/consts/std-XZ)
|
||||
* [`YZ`](kcl/consts/std-YZ)
|
||||
* [`ZERO`](kcl/consts/std-ZERO)
|
||||
* [`abs`](kcl/abs)
|
||||
* [`acos`](kcl/acos)
|
||||
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
|
||||
@ -134,9 +135,9 @@ layout: manual
|
||||
* [`yLine`](kcl/yLine)
|
||||
* [`yd`](kcl/yd)
|
||||
* **std::math**
|
||||
* [`E`](kcl/const_std-math-E)
|
||||
* [`PI`](kcl/const_std-math-PI)
|
||||
* [`TAU`](kcl/const_std-math-TAU)
|
||||
* [`E`](kcl/consts/std-math-E)
|
||||
* [`PI`](kcl/consts/std-math-PI)
|
||||
* [`TAU`](kcl/consts/std-math-TAU)
|
||||
* [`cos`](kcl/std-math-cos)
|
||||
* [`sin`](kcl/std-math-sin)
|
||||
* [`tan`](kcl/std-math-tan)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "KCL settings"
|
||||
title: "KCL Settings"
|
||||
excerpt: "Documentation of settings for the KCL language and Zoo Modeling App."
|
||||
layout: manual
|
||||
---
|
||||
@ -8,16 +8,16 @@ layout: manual
|
||||
|
||||
There are three levels of settings available in the KittyCAD modeling application:
|
||||
|
||||
1. [User Settings](/docs/kcl/settings/user.toml): Global settings that apply to all projects, stored in `user.toml`
|
||||
2. [Project Settings](/docs/kcl/settings/project.toml): Settings specific to a project, stored in `project.toml`
|
||||
1. [User Settings](/docs/kcl/settings/user): Global settings that apply to all projects, stored in `user.toml`
|
||||
2. [Project Settings](/docs/kcl/settings/project): Settings specific to a project, stored in `project.toml`
|
||||
3. Per-file Settings: Settings that apply to a single KCL file, specified using the `@settings` attribute
|
||||
|
||||
## Configuration Files
|
||||
|
||||
The KittyCAD modeling app uses TOML files for configuration:
|
||||
|
||||
* **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user.toml)
|
||||
* **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project.toml)
|
||||
* **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user)
|
||||
* **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project)
|
||||
|
||||
## Per-file settings
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -274,7 +274,6 @@ test.describe('Feature Tree pane', () => {
|
||||
currentArgKey: 'distance',
|
||||
currentArgValue: initialInput,
|
||||
headerArguments: {
|
||||
Selection: '1 face',
|
||||
Distance: initialInput,
|
||||
},
|
||||
highlightedHeaderArg: 'distance',
|
||||
@ -291,7 +290,6 @@ test.describe('Feature Tree pane', () => {
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Selection: '1 face',
|
||||
// The calculated value is shown in the argument summary
|
||||
Distance: initialInput,
|
||||
},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
@ -29,5 +29,5 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"kcl_version": "0.2.47"
|
||||
"kcl_version": "0.2.48"
|
||||
}
|
||||
@ -1127,7 +1127,6 @@ test.describe('Electron constraint tests', () => {
|
||||
path.join(bracketDir, 'main.kcl')
|
||||
)
|
||||
})
|
||||
const [clickHandler] = scene.makeMouseHelpers(600, 300)
|
||||
|
||||
await test.step('setup test', async () => {
|
||||
await homePage.expectState({
|
||||
@ -1144,8 +1143,12 @@ test.describe('Electron constraint tests', () => {
|
||||
})
|
||||
|
||||
await test.step('Double click to constrain', async () => {
|
||||
await clickHandler()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
// Enter sketch edit mode via feature tree
|
||||
await toolbar.openPane('feature-tree')
|
||||
const op = await toolbar.getFeatureTreeOperation('Sketch', 0)
|
||||
await op.dblclick()
|
||||
await toolbar.closePane('feature-tree')
|
||||
|
||||
const child = page
|
||||
.locator('.segment-length-label-text')
|
||||
.first()
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# This way we don't start and stop too many engine instances, putting pressure on our cloud.
|
||||
uses-engine = { max-threads = 4 }
|
||||
# If a test must run after the engine tests, we want to make sure the engine tests are done first.
|
||||
after-engine = { depends-on = ["uses-engine"], max-threads = 12 }
|
||||
after-engine = { max-threads = 12 }
|
||||
|
||||
[profile.default]
|
||||
slow-timeout = { period = "30s", terminate-after = 1 }
|
||||
|
||||
20
rust/Cargo.lock
generated
20
rust/Cargo.lock
generated
@ -1783,7 +1783,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1794,7 +1794,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-derive-docs"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1813,7 +1813,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1822,7 +1822,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server"
|
||||
version = "0.2.47"
|
||||
version = "0.2.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1843,7 +1843,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@ -1863,7 +1863,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.2.47"
|
||||
version = "0.2.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx 0.5.1",
|
||||
@ -1931,7 +1931,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.47"
|
||||
version = "0.3.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
@ -1946,7 +1946,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-test-server"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hyper 0.14.32",
|
||||
@ -1959,7 +1959,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-to-core"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1973,7 +1973,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
dependencies = [
|
||||
"bson",
|
||||
"console_error_panic_hook",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
[package]
|
||||
name = "kcl-bumper"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-api"
|
||||
rust-version = "1.76"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-directory-test-macro"
|
||||
description = "A tool for generating tests from a directory of kcl files"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-language-server-release"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name = "kcl-language-server"
|
||||
description = "A language server for KCL."
|
||||
authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
version = "0.2.47"
|
||||
version = "0.2.48"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.2.47"
|
||||
version = "0.2.48"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -21,7 +21,7 @@ use crate::{
|
||||
};
|
||||
|
||||
const TYPES_DIR: &str = "../../docs/kcl/types";
|
||||
const LANG_TOPICS: [&str; 4] = ["Types", "Modules", "Settings", "Known Issues"];
|
||||
const LANG_TOPICS: [&str; 5] = ["Types", "Modules", "Settings", "Known Issues", "Constants"];
|
||||
// These types are declared in std.
|
||||
const DECLARED_TYPES: [&str; 7] = ["number", "string", "tag", "bool", "Sketch", "Solid", "Plane"];
|
||||
|
||||
@ -298,6 +298,7 @@ fn init_handlebars() -> Result<handlebars::Handlebars<'static>> {
|
||||
hbs.register_template_string("propertyType", include_str!("templates/propertyType.hbs"))?;
|
||||
hbs.register_template_string("schema", include_str!("templates/schema.hbs"))?;
|
||||
hbs.register_template_string("index", include_str!("templates/index.hbs"))?;
|
||||
hbs.register_template_string("consts-index", include_str!("templates/consts-index.hbs"))?;
|
||||
hbs.register_template_string("function", include_str!("templates/function.hbs"))?;
|
||||
hbs.register_template_string("const", include_str!("templates/const.hbs"))?;
|
||||
hbs.register_template_string("type", include_str!("templates/type.hbs"))?;
|
||||
@ -312,6 +313,9 @@ fn generate_index(combined: &IndexMap<String, Box<dyn StdLibFn>>, kcl_lib: &[Doc
|
||||
let mut functions = HashMap::new();
|
||||
functions.insert("std".to_owned(), Vec::new());
|
||||
|
||||
let mut constants = HashMap::new();
|
||||
constants.insert("std".to_owned(), Vec::new());
|
||||
|
||||
for key in combined.keys() {
|
||||
let internal_fn = combined
|
||||
.get(key)
|
||||
@ -337,6 +341,13 @@ fn generate_index(combined: &IndexMap<String, Box<dyn StdLibFn>>, kcl_lib: &[Doc
|
||||
DocData::Const(c) => (c.name.clone(), d.file_name()),
|
||||
DocData::Ty(t) => (t.name.clone(), d.file_name()),
|
||||
});
|
||||
|
||||
if let DocData::Const(c) = d {
|
||||
constants
|
||||
.entry(d.mod_name())
|
||||
.or_default()
|
||||
.push((c.name.clone(), d.file_name()));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO we should sub-divide into types, constants, and functions.
|
||||
@ -362,7 +373,7 @@ fn generate_index(combined: &IndexMap<String, Box<dyn StdLibFn>>, kcl_lib: &[Doc
|
||||
.map(|name| {
|
||||
json!({
|
||||
"name": name,
|
||||
"file_name": name.to_lowercase().replace(' ', "-"),
|
||||
"file_name": name.to_lowercase().replace(' ', "-").replace("constants", "consts"),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
@ -375,6 +386,31 @@ fn generate_index(combined: &IndexMap<String, Box<dyn StdLibFn>>, kcl_lib: &[Doc
|
||||
|
||||
expectorate::assert_contents("../../docs/kcl/index.md", &output);
|
||||
|
||||
// Generate the index for the constants.
|
||||
let mut sorted_consts: Vec<_> = constants
|
||||
.into_iter()
|
||||
.map(|(m, mut consts)| {
|
||||
consts.sort();
|
||||
let val = json!({
|
||||
"name": m,
|
||||
"consts": consts.into_iter().map(|(n, f)| json!({
|
||||
"name": n,
|
||||
"file_name": f,
|
||||
})).collect::<Vec<_>>(),
|
||||
});
|
||||
(m, val)
|
||||
})
|
||||
.collect();
|
||||
sorted_consts.sort_by(|t1, t2| t1.0.cmp(&t2.0));
|
||||
let data: Vec<_> = sorted_consts.into_iter().map(|(_, val)| val).collect();
|
||||
let data = json!({
|
||||
"consts": data,
|
||||
});
|
||||
|
||||
let output = hbs.render("consts-index", &data)?;
|
||||
|
||||
expectorate::assert_contents("../../docs/kcl/consts.md", &output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -405,7 +441,7 @@ fn generate_example(index: usize, src: &str, props: &ExampleProperties, file_nam
|
||||
}))
|
||||
}
|
||||
|
||||
fn generate_type_from_kcl(ty: &TyData, file_name: String) -> Result<()> {
|
||||
fn generate_type_from_kcl(ty: &TyData, file_name: String, example_name: String) -> Result<()> {
|
||||
if ty.properties.doc_hidden {
|
||||
return Ok(());
|
||||
}
|
||||
@ -416,7 +452,7 @@ fn generate_type_from_kcl(ty: &TyData, file_name: String) -> Result<()> {
|
||||
.examples
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, example)| generate_example(index, &example.0, &example.1, &file_name))
|
||||
.filter_map(|(index, example)| generate_example(index, &example.0, &example.1, &example_name))
|
||||
.collect();
|
||||
|
||||
let data = json!({
|
||||
@ -428,7 +464,7 @@ fn generate_type_from_kcl(ty: &TyData, file_name: String) -> Result<()> {
|
||||
});
|
||||
|
||||
let output = hbs.render("kclType", &data)?;
|
||||
expectorate::assert_contents(format!("../../docs/kcl/types/{}.md", file_name), &output);
|
||||
expectorate::assert_contents(format!("../../docs/kcl/{}.md", file_name), &output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -480,7 +516,7 @@ fn generate_function_from_kcl(function: &FnData, file_name: String) -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_const_from_kcl(cnst: &ConstData, file_name: String) -> Result<()> {
|
||||
fn generate_const_from_kcl(cnst: &ConstData, file_name: String, example_name: String) -> Result<()> {
|
||||
if cnst.properties.doc_hidden {
|
||||
return Ok(());
|
||||
}
|
||||
@ -490,7 +526,7 @@ fn generate_const_from_kcl(cnst: &ConstData, file_name: String) -> Result<()> {
|
||||
.examples
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, example)| generate_example(index, &example.0, &example.1, &file_name))
|
||||
.filter_map(|(index, example)| generate_example(index, &example.0, &example.1, &example_name))
|
||||
.collect();
|
||||
|
||||
let data = json!({
|
||||
@ -1028,8 +1064,8 @@ fn test_generate_stdlib_markdown_docs() {
|
||||
for d in &kcl_std {
|
||||
match d {
|
||||
DocData::Fn(f) => generate_function_from_kcl(f, d.file_name()).unwrap(),
|
||||
DocData::Const(c) => generate_const_from_kcl(c, d.file_name()).unwrap(),
|
||||
DocData::Ty(t) => generate_type_from_kcl(t, d.file_name()).unwrap(),
|
||||
DocData::Const(c) => generate_const_from_kcl(c, d.file_name(), d.example_name()).unwrap(),
|
||||
DocData::Ty(t) => generate_type_from_kcl(t, d.file_name(), d.example_name()).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1061,7 +1097,8 @@ fn test_generate_stdlib_json_schema() {
|
||||
async fn test_code_in_topics() {
|
||||
let mut join_set = JoinSet::new();
|
||||
for name in LANG_TOPICS {
|
||||
let filename = format!("../../docs/kcl/{}.md", name.to_lowercase().replace(' ', "-"));
|
||||
let filename =
|
||||
format!("../../docs/kcl/{}.md", name.to_lowercase().replace(' ', "-")).replace("constants", "consts");
|
||||
let mut file = File::open(&filename).unwrap();
|
||||
let mut text = String::new();
|
||||
file.read_to_string(&mut text).unwrap();
|
||||
|
||||
@ -116,10 +116,18 @@ impl DocData {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn file_name(&self) -> String {
|
||||
match self {
|
||||
DocData::Fn(f) => f.qual_name.replace("::", "-"),
|
||||
DocData::Const(c) => format!("consts/{}", c.qual_name.replace("::", "-")),
|
||||
DocData::Ty(t) => format!("types/{}", t.name.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn example_name(&self) -> String {
|
||||
match self {
|
||||
DocData::Fn(f) => f.qual_name.replace("::", "-"),
|
||||
DocData::Const(c) => format!("const_{}", c.qual_name.replace("::", "-")),
|
||||
// TODO might want to change this
|
||||
DocData::Ty(t) => t.name.clone(),
|
||||
}
|
||||
}
|
||||
@ -872,7 +880,7 @@ mod test {
|
||||
Ok(img) => img,
|
||||
};
|
||||
twenty_twenty::assert_image(
|
||||
format!("tests/outputs/serial_test_example_{}{i}.png", d.file_name()),
|
||||
format!("tests/outputs/serial_test_example_{}{i}.png", d.example_name()),
|
||||
&result,
|
||||
0.99,
|
||||
);
|
||||
|
||||
17
rust/kcl-lib/src/docs/templates/consts-index.hbs
vendored
Normal file
17
rust/kcl-lib/src/docs/templates/consts-index.hbs
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: "KCL Constants"
|
||||
excerpt: "Documentation for the KCL constants."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
{{#each consts}}
|
||||
|
||||
### `{{name}}`
|
||||
|
||||
{{#each consts}}
|
||||
- [`{{name}}`](/docs/kcl/{{file_name}})
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
|
||||
@ -64,8 +64,6 @@ pub struct ExecOutcome {
|
||||
/// Operations that have been performed in execution order, for display in
|
||||
/// the Feature Tree.
|
||||
pub operations: Vec<Operation>,
|
||||
/// Output map of UUIDs to artifacts.
|
||||
pub artifacts: IndexMap<ArtifactId, Artifact>,
|
||||
/// Output commands to allow building the artifact graph by the caller.
|
||||
pub artifact_commands: Vec<ArtifactCommand>,
|
||||
/// Output artifact graph.
|
||||
|
||||
@ -123,7 +123,6 @@ impl ExecState {
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect(),
|
||||
operations: self.global.operations,
|
||||
artifacts: self.global.artifacts,
|
||||
artifact_commands: self.global.artifact_commands,
|
||||
artifact_graph: self.global.artifact_graph,
|
||||
errors: self.global.errors,
|
||||
@ -146,7 +145,6 @@ impl ExecState {
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect(),
|
||||
operations: Default::default(),
|
||||
artifacts: Default::default(),
|
||||
artifact_commands: Default::default(),
|
||||
artifact_graph: Default::default(),
|
||||
errors: self.global.errors,
|
||||
|
||||
@ -39,8 +39,8 @@ base_unit = "mm"
|
||||
text_wrapping = false
|
||||
"#;
|
||||
|
||||
const PROJECT_SETTINGS_DOC_PATH: &str = "../../docs/kcl/settings/project.toml.md";
|
||||
const USER_SETTINGS_DOC_PATH: &str = "../../docs/kcl/settings/user.toml.md";
|
||||
const PROJECT_SETTINGS_DOC_PATH: &str = "../../docs/kcl/settings/project.md";
|
||||
const USER_SETTINGS_DOC_PATH: &str = "../../docs/kcl/settings/user.md";
|
||||
|
||||
fn init_handlebars() -> handlebars::Handlebars<'static> {
|
||||
let mut hbs = handlebars::Handlebars::new();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Result of parsing array_elem_pop.kcl
|
||||
---
|
||||
{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Result of parsing array_elem_pop_empty_fail.kcl
|
||||
---
|
||||
{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
source: kcl/src/simulation_tests.rs
|
||||
source: kcl-lib/src/simulation_tests.rs
|
||||
description: Error from executing array_elem_pop_empty_fail.kcl
|
||||
---
|
||||
KCL Semantic error
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-python-bindings"
|
||||
version = "0.3.47"
|
||||
version = "0.3.48"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/kittycad/modeling-app"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-test-server"
|
||||
description = "A test server for KCL"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-to-core"
|
||||
description = "Utility methods to convert kcl to engine core executable tests"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kcl-wasm-lib"
|
||||
version = "0.1.47"
|
||||
version = "0.1.48"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
rust-version = "1.83"
|
||||
|
||||
@ -17,7 +17,12 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
||||
if (!selectedCommand?.args) return undefined
|
||||
const s = { ...selectedCommand.args }
|
||||
for (const [name, arg] of Object.entries(s)) {
|
||||
if (arg.hidden) delete s[name]
|
||||
if (
|
||||
typeof arg.hidden === 'function'
|
||||
? arg.hidden(commandBarState.context)
|
||||
: arg.hidden
|
||||
)
|
||||
delete s[name]
|
||||
}
|
||||
return s
|
||||
}, [selectedCommand])
|
||||
|
||||
@ -8,9 +8,32 @@ import {
|
||||
faTrash,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
/** Type narrowing function of unknown error to a string */
|
||||
function errorMessage(error: unknown): string {
|
||||
if (isRouteErrorResponse(error)) {
|
||||
return `${error.status} ${error.statusText}`
|
||||
} else if (error != undefined && error instanceof Error) {
|
||||
return error.message
|
||||
} else if (error && typeof error === 'object') {
|
||||
return JSON.stringify(error)
|
||||
} else if (typeof error === 'string') {
|
||||
return error
|
||||
} else {
|
||||
return 'Unknown error'
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate a GitHub issue URL from the error */
|
||||
function generateToUrl(error: unknown) {
|
||||
const title: string = 'An unexpected error occurred'
|
||||
const body = errorMessage(error)
|
||||
const result = `https://github.com/KittyCAD/modeling-app/issues/new?title=${title}&body=${body}`
|
||||
return result
|
||||
}
|
||||
|
||||
export const ErrorPage = () => {
|
||||
let error = useRouteError()
|
||||
|
||||
// We log the error to the console no matter what
|
||||
console.error('error', error)
|
||||
|
||||
return (
|
||||
@ -19,11 +42,9 @@ export const ErrorPage = () => {
|
||||
<h1 className="text-4xl mb-8 font-bold" data-testid="unexpected-error">
|
||||
An unexpected error occurred
|
||||
</h1>
|
||||
{isRouteErrorResponse(error) && (
|
||||
<p className="mb-8">
|
||||
{error.status}: {error.data}
|
||||
</p>
|
||||
)}
|
||||
<p className="mb-8 w-full overflow-aut">
|
||||
<>{errorMessage(error)}</>
|
||||
</p>
|
||||
<div className="flex justify-between gap-2 mt-6">
|
||||
{isDesktop() && (
|
||||
<ActionButton
|
||||
@ -54,7 +75,7 @@ export const ErrorPage = () => {
|
||||
<ActionButton
|
||||
Element="externalLink"
|
||||
iconStart={{ icon: faBug }}
|
||||
to="https://github.com/KittyCAD/modeling-app/issues/new"
|
||||
to={generateToUrl(error)}
|
||||
>
|
||||
Report Bug
|
||||
</ActionButton>
|
||||
|
||||
@ -7,7 +7,7 @@ import toast from 'react-hot-toast'
|
||||
import { editorManager } from 'lib/singletons'
|
||||
import { Annotation, Transaction } from '@codemirror/state'
|
||||
import { EditorView, KeyBinding } from '@codemirror/view'
|
||||
import { recast, Program, parse } from 'lang/wasm'
|
||||
import { recast, Program, parse, SourceRange } from 'lang/wasm'
|
||||
import { err, reportRejection } from 'lib/trap'
|
||||
import { Compartment } from '@codemirror/state'
|
||||
import { history } from '@codemirror/commands'
|
||||
@ -57,6 +57,10 @@ export default class CodeManager {
|
||||
return this._code
|
||||
}
|
||||
|
||||
getCodeAtRange(range: SourceRange) {
|
||||
return this._code.slice(range[0], range[1])
|
||||
}
|
||||
|
||||
localStoragePersistCode(): string {
|
||||
return safeLSGetItem(PERSIST_CODE_KEY) || ''
|
||||
}
|
||||
|
||||
@ -295,7 +295,6 @@ export const isPathToNodeNumber = (
|
||||
export interface ExecState {
|
||||
variables: { [key in string]?: KclValue }
|
||||
operations: Operation[]
|
||||
artifacts: { [key in ArtifactId]?: RustArtifact }
|
||||
artifactCommands: ArtifactCommand[]
|
||||
artifactGraph: ArtifactGraph
|
||||
errors: CompilationError[]
|
||||
@ -310,7 +309,6 @@ export function emptyExecState(): ExecState {
|
||||
return {
|
||||
variables: {},
|
||||
operations: [],
|
||||
artifacts: {},
|
||||
artifactCommands: [],
|
||||
artifactGraph: defaultArtifactGraph(),
|
||||
errors: [],
|
||||
@ -337,7 +335,6 @@ function execStateFromRust(
|
||||
return {
|
||||
variables: execOutcome.variables,
|
||||
operations: execOutcome.operations,
|
||||
artifacts: execOutcome.artifacts,
|
||||
artifactCommands: execOutcome.artifactCommands,
|
||||
artifactGraph,
|
||||
errors: execOutcome.errors,
|
||||
@ -349,7 +346,6 @@ function mockExecStateFromRust(execOutcome: RustExecOutcome): ExecState {
|
||||
return {
|
||||
variables: execOutcome.variables,
|
||||
operations: execOutcome.operations,
|
||||
artifacts: execOutcome.artifacts,
|
||||
artifactCommands: execOutcome.artifactCommands,
|
||||
artifactGraph: new Map<ArtifactId, Artifact>(),
|
||||
errors: execOutcome.errors,
|
||||
|
||||
@ -69,6 +69,8 @@ export type ModelingCommandSchema = {
|
||||
edge: Selections
|
||||
}
|
||||
Fillet: {
|
||||
// Enables editing workflow
|
||||
nodeToEdit?: PathToNode
|
||||
selection: Selections
|
||||
radius: KclCommandValue
|
||||
}
|
||||
@ -319,6 +321,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
multiple: false, // TODO: multiple selection
|
||||
required: true,
|
||||
skip: true,
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
// result: {
|
||||
// inputType: 'options',
|
||||
@ -407,6 +410,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
multiple: false, // TODO: multiple selection
|
||||
required: true,
|
||||
skip: true,
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
axisOrEdge: {
|
||||
inputType: 'options',
|
||||
@ -416,6 +420,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
{ name: 'Axis', isCurrent: true, value: 'Axis' },
|
||||
{ name: 'Edge', isCurrent: false, value: 'Edge' },
|
||||
],
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
axis: {
|
||||
required: (commandContext) =>
|
||||
@ -437,6 +442,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
selectionTypes: ['segment', 'sweepEdge', 'edgeCutEdge'],
|
||||
multiple: false,
|
||||
validation: revolveAxisValidator,
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
angle: {
|
||||
inputType: 'kcl',
|
||||
@ -534,12 +540,21 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
status: 'development',
|
||||
needsReview: true,
|
||||
args: {
|
||||
nodeToEdit: {
|
||||
description:
|
||||
'Path to the node in the AST to edit. Never shown to the user.',
|
||||
skip: true,
|
||||
inputType: 'text',
|
||||
required: false,
|
||||
hidden: true,
|
||||
},
|
||||
selection: {
|
||||
inputType: 'selection',
|
||||
selectionTypes: ['segment', 'sweepEdge', 'edgeCutEdge'],
|
||||
multiple: true,
|
||||
required: true,
|
||||
skip: false,
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
warningMessage:
|
||||
'Fillets cannot touch other fillets yet. This is under development.',
|
||||
},
|
||||
|
||||
@ -120,7 +120,12 @@ export type CommandArgumentConfig<
|
||||
) => boolean)
|
||||
warningMessage?: string
|
||||
/** If `true`, arg is used as passed-through data, never for user input */
|
||||
hidden?: boolean
|
||||
hidden?:
|
||||
| boolean
|
||||
| ((
|
||||
commandBarContext: { argumentsToSubmit: Record<string, unknown> }, // Should be the commandbarMachine's context, but it creates a circular dependency
|
||||
machineContext?: C
|
||||
) => boolean)
|
||||
skip?: boolean
|
||||
/** For showing a summary display of the current value, such as in
|
||||
* the command bar's header
|
||||
@ -236,7 +241,12 @@ export type CommandArgument<
|
||||
machineContext?: ContextFrom<T>
|
||||
) => boolean)
|
||||
/** If `true`, arg is used as passed-through data, never for user input */
|
||||
hidden?: boolean
|
||||
hidden?:
|
||||
| boolean
|
||||
| ((
|
||||
commandBarContext: { argumentsToSubmit: Record<string, unknown> }, // Should be the commandbarMachine's context, but it creates a circular dependency
|
||||
machineContext?: ContextFrom<T>
|
||||
) => boolean)
|
||||
skip?: boolean
|
||||
machineActor?: Actor<T>
|
||||
warningMessage?: string
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import { CustomIconName } from 'components/CustomIcon'
|
||||
import { Artifact, getArtifactOfTypes } from 'lang/std/artifactGraph'
|
||||
import {
|
||||
Artifact,
|
||||
getArtifactByPredicate,
|
||||
getArtifactOfTypes,
|
||||
getArtifactsOfTypes,
|
||||
} from 'lang/std/artifactGraph'
|
||||
import { Operation } from '@rust/kcl-lib/bindings/Operation'
|
||||
import { codeManager, engineCommandManager, kclManager } from './singletons'
|
||||
import { err } from './trap'
|
||||
@ -293,6 +298,84 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const prepareToEditFillet: PrepareToEditCallback = async ({
|
||||
artifact,
|
||||
operation,
|
||||
}) => {
|
||||
const baseCommand = {
|
||||
name: 'Fillet',
|
||||
groupId: 'modeling',
|
||||
}
|
||||
if (
|
||||
operation.type !== 'StdLibCall' ||
|
||||
!operation.labeledArgs ||
|
||||
operation.name !== 'fillet' ||
|
||||
!('tags' in operation.labeledArgs) ||
|
||||
!('radius' in operation.labeledArgs) ||
|
||||
!operation.labeledArgs.radius ||
|
||||
!artifact ||
|
||||
artifact.type !== 'edgeCut' ||
|
||||
artifact.subType !== 'fillet'
|
||||
) {
|
||||
return baseCommand
|
||||
}
|
||||
|
||||
if (
|
||||
!operation.labeledArgs.tags ||
|
||||
operation.labeledArgs.tags.value.type !== 'Array'
|
||||
) {
|
||||
return baseCommand
|
||||
}
|
||||
const edgeIds = operation.labeledArgs.tags.value.value.map((tag) =>
|
||||
tag.type === 'Uuid' ? tag.value : ''
|
||||
)
|
||||
if (!edgeIds.every((id) => id)) {
|
||||
return baseCommand
|
||||
}
|
||||
|
||||
const edges = getArtifactsOfTypes(
|
||||
{
|
||||
keys: edgeIds,
|
||||
types: ['sweepEdge', 'segment'],
|
||||
},
|
||||
engineCommandManager.artifactGraph
|
||||
)
|
||||
const selection: ModelingCommandSchema['Fillet']['selection'] = {
|
||||
graphSelections: edges
|
||||
.values()
|
||||
.map((edge, index) => ({
|
||||
artifact: edge,
|
||||
codeRef: {
|
||||
range: operation.labeledArgs.tags?.sourceRange ?? [0, 0, 0],
|
||||
pathToNode: getNodePathFromSourceRange(
|
||||
kclManager.ast,
|
||||
operation.labeledArgs.tags?.sourceRange ?? [0, 0, 0]
|
||||
),
|
||||
},
|
||||
}))
|
||||
.toArray(),
|
||||
otherSelections: [],
|
||||
}
|
||||
const maybeRadius = await stringToKclExpression(
|
||||
codeManager.getCodeAtRange(operation.labeledArgs.radius.sourceRange)
|
||||
)
|
||||
if (err(maybeRadius) || 'errors' in maybeRadius) return baseCommand
|
||||
|
||||
const argDefaultValues: ModelingCommandSchema['Fillet'] = {
|
||||
nodeToEdit: getNodePathFromSourceRange(
|
||||
kclManager.ast,
|
||||
sourceRangeFromRust(operation.sourceRange)
|
||||
),
|
||||
radius: maybeRadius,
|
||||
selection,
|
||||
}
|
||||
|
||||
return {
|
||||
...baseCommand,
|
||||
argDefaultValues,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A map of standard library calls to their corresponding information
|
||||
* for use in the feature tree UI.
|
||||
@ -312,6 +395,7 @@ export const stdLibMap: Record<string, StdLibCallInfo> = {
|
||||
fillet: {
|
||||
label: 'Fillet',
|
||||
icon: 'fillet3d',
|
||||
prepareToEdit: prepareToEditFillet,
|
||||
},
|
||||
helix: {
|
||||
label: 'Helix',
|
||||
|
||||
@ -134,8 +134,10 @@ export const commandBarMachine = setup({
|
||||
// that is, the first argument that is not already in the argumentsToSubmit
|
||||
// or hidden, or that is not undefined, or that is not marked as "skippable".
|
||||
// TODO validate the type of the existing arguments
|
||||
const nonHiddenArgs = Object.entries(selectedCommand.args).filter(
|
||||
(a) => !a[1].hidden
|
||||
const nonHiddenArgs = Object.entries(selectedCommand.args).filter((a) =>
|
||||
a[1].hidden && typeof a[1].hidden === 'function'
|
||||
? !a[1].hidden(context)
|
||||
: !a[1].hidden
|
||||
)
|
||||
let argIndex = 0
|
||||
|
||||
@ -260,7 +262,11 @@ export const commandBarMachine = setup({
|
||||
},
|
||||
'All arguments are skippable': ({ context }) => {
|
||||
return Object.values(context.selectedCommand!.args!).every(
|
||||
(argConfig) => argConfig.skip || argConfig.hidden
|
||||
(argConfig) =>
|
||||
argConfig.skip ||
|
||||
(typeof argConfig.hidden === 'function'
|
||||
? argConfig.hidden(context)
|
||||
: argConfig.hidden)
|
||||
)
|
||||
},
|
||||
'Has selected command': ({ context }) => !!context.selectedCommand,
|
||||
|
||||
Reference in New Issue
Block a user