Add stdlib functions for getting sketch profile start and its components (#2373)

* Add stdlib functions for getting sketch profile start and its components

* Fix it up and actually generate snapshots

* cargo fmt

* Use `.to` instead of `.from`

* Update docs with EXPECTORATE=overwrite

* Add README

* fmt

* Update flow test to account for more autocompletion options when typing "start"

---------

Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2024-05-21 03:44:02 -04:00
committed by GitHub
parent 793b7407f6
commit 82b03a9d47
13 changed files with 3696 additions and 6 deletions

View File

@ -59,7 +59,9 @@ followed by:
``` ```
yarn build:wasm-dev yarn build:wasm-dev
``` ```
or if you have the gh cli installed or if you have the gh cli installed
``` ```
./get-latest-wasm-bundle.sh # this will download the latest main wasm bundle ./get-latest-wasm-bundle.sh # this will download the latest main wasm bundle
``` ```
@ -100,6 +102,7 @@ yarn test
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro/) tests, in interactive mode by default. Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro/) tests, in interactive mode by default.
For running the rust (not tauri rust though) only, you can For running the rust (not tauri rust though) only, you can
```bash ```bash
cd src/wasm-lib cd src/wasm-lib
cargo test cargo test
@ -162,6 +165,7 @@ console.log(
- `) - `)
) )
``` ```
grab the md list and delete any that are older than the last bump grab the md list and delete any that are older than the last bump
2. Merge the PR 2. Merge the PR
@ -191,23 +195,26 @@ $ cargo +nightly fuzz run parser
For more information on fuzzing you can check out For more information on fuzzing you can check out
[this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html). [this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html).
### Playwright ### Playwright
First time running plawright locally, you'll need to add the secrets file First time running plawright locally, you'll need to add the secrets file
```bash ```bash
touch ./e2e/playwright/playwright-secrets.env touch ./e2e/playwright/playwright-secrets.env
printf 'token="your-token"\nsnapshottoken="your-snapshot-token"' > ./e2e/playwright/playwright-secrets.env printf 'token="your-token"\nsnapshottoken="your-snapshot-token"' > ./e2e/playwright/playwright-secrets.env
``` ```
then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens
then: then:
run playwright run playwright
``` ```
yarn playwright test yarn playwright test
``` ```
run a specific test suite run a specific test suite
``` ```
yarn playwright test src/e2e-tests/example.spec.ts yarn playwright test src/e2e-tests/example.spec.ts
``` ```
@ -216,14 +223,17 @@ run a specific test change the test from `test('...` to `test.only('...`
(note if you commit this, the tests will instantly fail without running any of the tests) (note if you commit this, the tests will instantly fail without running any of the tests)
run headed run headed
``` ```
yarn playwright test --headed yarn playwright test --headed
``` ```
run with step through debugger run with step through debugger
``` ```
PWDEBUG=1 yarn playwright test PWDEBUG=1 yarn playwright test
``` ```
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying. However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code. With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
@ -268,7 +278,6 @@ Where `./store` should look like this
</details> </details>
However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use. However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use.
#### Some notes on CI #### Some notes on CI
@ -299,3 +308,7 @@ PS: for the debug panel, the following JSON is useful for snapping the camera
``` ```
</details> </details>
## KCL
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).

View File

@ -56,6 +56,9 @@ layout: manual
* [`patternLinear3d`](kcl/patternLinear3d) * [`patternLinear3d`](kcl/patternLinear3d)
* [`pi`](kcl/pi) * [`pi`](kcl/pi)
* [`pow`](kcl/pow) * [`pow`](kcl/pow)
* [`profileStart`](kcl/profileStart)
* [`profileStartX`](kcl/profileStartX)
* [`profileStartY`](kcl/profileStartY)
* [`revolve`](kcl/revolve) * [`revolve`](kcl/revolve)
* [`segAng`](kcl/segAng) * [`segAng`](kcl/segAng)
* [`segEndX`](kcl/segEndX) * [`segEndX`](kcl/segEndX)

206
docs/kcl/profileStart.md Normal file

File diff suppressed because one or more lines are too long

201
docs/kcl/profileStartX.md Normal file

File diff suppressed because one or more lines are too long

200
docs/kcl/profileStartY.md Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -646,8 +646,8 @@ test('Auto complete works', async ({ page }) => {
await page.click('.cm-content') await page.click('.cm-content')
await page.keyboard.type('const part001 = start') await page.keyboard.type('const part001 = start')
// expect there to be three auto complete options // expect there to be six auto complete options
await expect(page.locator('.cm-completionLabel')).toHaveCount(3) await expect(page.locator('.cm-completionLabel')).toHaveCount(6)
await page.getByText('startSketchOn').click() await page.getByText('startSketchOn').click()
await page.keyboard.type("'XZ'") await page.keyboard.type("'XZ'")
await page.keyboard.press('Tab') await page.keyboard.press('Tab')

View File

@ -0,0 +1,20 @@
# KCL
Our language for defining geometry and working with our Geometry Engine efficiently. Short for KittyCAD Language, named after our Design API.
## Contributing a standard library function
We've built a lot of tooling to make contributing to KCL easier. If you are interested in contributing a new standard library function to KCL, here is the rough process:
1. Open just the wasm-lib folder in your editor of choice. VS Code, for example, struggles to run rust-analyzer on the entire modeling-app directory because it's such a turducken of TS and Rust code.
2. Find the definition for similar standard library functions in `./kcl/src/std` and place your new one near it or in the same category file.
3. Add your new code. A new standard library function consists of:
4. A `pub async` of the actual standard library function in Rust
5. A doc comment block containing at least one example using your new standard library function (the Rust compiler will error if you don't provide an example our teammates are dope)
6. A `stdlib` macro providing the name that will need to be written by KCL users to use the function (this is usually a camelCase version of your Rust implementation, which is named with snake_case)
7. An inner function that is published only to the crate
8. Add your new standard library function to [the long list of CORE_FNS in mod.rs](https://github.com/KittyCAD/modeling-app/blob/main/src/wasm-lib/kcl/src/std/mod.rs#L42)
9. Get a production Zoo dev token and run `export KITTYCAD_API_TOKEN=your-token-here` in a terminal
10. Run `TWENTY_TWENTY=overwrite cargo nextest run --workspace --no-fail-fast` to take snapshot tests of your example code running in the engine
11. Run `EXPECTORATE=overwrite cargo test --all generate_stdlib -- --nocapture` to generate new Markdown documentation for your function that will be used [to generate docs on our website](https://zoo.dev/docs/kcl).
12. Create a PR in GitHub.

View File

@ -68,6 +68,9 @@ lazy_static! {
Box::new(crate::std::sketch::StartSketchAt), Box::new(crate::std::sketch::StartSketchAt),
Box::new(crate::std::sketch::StartSketchOn), Box::new(crate::std::sketch::StartSketchOn),
Box::new(crate::std::sketch::StartProfileAt), Box::new(crate::std::sketch::StartProfileAt),
Box::new(crate::std::sketch::ProfileStartX),
Box::new(crate::std::sketch::ProfileStartY),
Box::new(crate::std::sketch::ProfileStart),
Box::new(crate::std::sketch::Close), Box::new(crate::std::sketch::Close),
Box::new(crate::std::sketch::Arc), Box::new(crate::std::sketch::Arc),
Box::new(crate::std::sketch::TangentialArc), Box::new(crate::std::sketch::TangentialArc),

View File

@ -12,7 +12,7 @@ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{ executor::{
BasePath, ExtrudeGroup, ExtrudeSurface, Face, GeoMeta, MemoryItem, Path, Plane, PlaneType, Point2d, Point3d, BasePath, ExtrudeGroup, ExtrudeSurface, Face, GeoMeta, MemoryItem, Path, Plane, PlaneType, Point2d, Point3d,
Position, Rotation, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, Position, Rotation, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, UserVal,
}, },
std::{ std::{
utils::{ utils::{
@ -1214,6 +1214,78 @@ pub(crate) async fn inner_start_profile_at(
Ok(Box::new(sketch_group)) Ok(Box::new(sketch_group))
} }
/// Returns the X component of the sketch profile start point.
pub async fn profile_start_x(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group: Box<SketchGroup> = args.get_sketch_group()?;
let x = inner_profile_start_x(sketch_group)?;
args.make_user_val_from_f64(x)
}
/// ```no_run
/// const sketch001 = startSketchOn('XY')
/// |> startProfileAt([5, 2], %)
/// |> angledLine([-26.6, 50], %)
/// |> angledLine([90, 50], %)
/// |> angledLineToX({ angle: 30, to: profileStartX(%) }, %)
/// ```
#[stdlib {
name = "profileStartX"
}]
pub(crate) fn inner_profile_start_x(sketch_group: Box<SketchGroup>) -> Result<f64, KclError> {
Ok(sketch_group.start.to[0])
}
/// Returns the Y component of the sketch profile start point.
pub async fn profile_start_y(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group: Box<SketchGroup> = args.get_sketch_group()?;
let x = inner_profile_start_y(sketch_group)?;
args.make_user_val_from_f64(x)
}
/// ```no_run
/// const sketch001 = startSketchOn('XY')
/// |> startProfileAt([5, 2], %)
/// |> angledLine({ angle: -60, length: 14 }, %)
/// |> angledLineToY({ angle: 30, to: profileStartY(%) }, %)
/// ```
#[stdlib {
name = "profileStartY"
}]
pub(crate) fn inner_profile_start_y(sketch_group: Box<SketchGroup>) -> Result<f64, KclError> {
Ok(sketch_group.start.to[1])
}
/// Returns the sketch profile start point.
pub async fn profile_start(args: Args) -> Result<MemoryItem, KclError> {
let sketch_group: Box<SketchGroup> = args.get_sketch_group()?;
let point = inner_profile_start(sketch_group)?;
Ok(MemoryItem::UserVal(UserVal {
value: serde_json::to_value(point).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to convert point to json: {}", e),
source_ranges: vec![args.source_range],
})
})?,
meta: Default::default(),
}))
}
/// ```no_run
/// const sketch001 = startSketchOn('XY')
/// |> startProfileAt([5, 2], %)
/// |> angledLine({ angle: 120, length: 50 }, %, 'seg01')
/// |> angledLine({ angle: segAng('seg01', %) + 120, length: 50 }, %)
/// |> lineTo(profileStart(%), %)
/// |> close(%)
/// |> extrude(20, %)
/// ```
#[stdlib {
name = "profileStart"
}]
pub(crate) fn inner_profile_start(sketch_group: Box<SketchGroup>) -> Result<[f64; 2], KclError> {
Ok(sketch_group.start.to)
}
/// Close the current sketch. /// Close the current sketch.
pub async fn close(args: Args) -> Result<MemoryItem, KclError> { pub async fn close(args: Args) -> Result<MemoryItem, KclError> {
let (sketch_group, tag): (Box<SketchGroup>, Option<String>) = args.get_sketch_group_and_optional_tag()?; let (sketch_group, tag): (Box<SketchGroup>, Option<String>) = args.get_sketch_group_and_optional_tag()?;

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB