Compare commits

...

47 Commits

Author SHA1 Message Date
440eb2636a Cut release v0.21.6 (#2450)
* Cut release v0.21.6

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger ci

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-22 12:05:44 +10:00
344e72d7ec Cam fix (#2448)
* Revert "sketch dies on exit XY sketch (#2397)"

This reverts commit 75c6ae6e66.

* cam fix

* fmt
2024-05-22 01:19:13 +00:00
ec7b733a0d fix project list showing projects of double clicked files (#2441)
* make sure there is at least one kcl file in the dir to show in list

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

* open the correct file not assuming main.kcl

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

* add file path tests

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

* update settings paths

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

* new images

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-21 18:14:49 -07:00
63159c1cb8 fix reset settings in browser (#2434)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-21 13:33:52 -07:00
df62a995b5 Reset data channel seq every connect (closes #336) (#2431)
Reset inSequence back to 1 every time we connect to the Engine,
otherwise we'll continue to think the current sequence is a high number
(while the engine has no memory of the last session -- and may even be a
new engine instance!) and ignore messages until we pass that counter
again.

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>
2024-05-21 14:52:14 -04:00
fa762c1c4d throw error on both ranges (#2428)
* highlight both ranges

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

* add playwright test

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-21 00:49:57 -07:00
82b03a9d47 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>
2024-05-21 00:44:02 -07:00
793b7407f6 add TS ast walker (#2425) 2024-05-21 16:44:08 +10:00
040bcc2c09 bump zip (#2423)
* bump zip

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

* rerender images

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

* fix markdown

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-21 05:07:56 +00:00
ae2e219394 fix empty tag on sketch on face (#2424)
add test

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-20 21:59:56 -07:00
a83f549257 Bump @tauri-apps/plugin-fs from 2.0.0-beta.2 to 2.0.0-beta.3 (#2403)
Bumps @tauri-apps/plugin-fs from 2.0.0-beta.2 to 2.0.0-beta.3.

---
updated-dependencies:
- dependency-name: "@tauri-apps/plugin-fs"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:37:27 -07:00
3871d2858f Bump @tauri-apps/plugin-updater from 2.0.0-beta.2 to 2.0.0-beta.3 (#2404)
Bumps @tauri-apps/plugin-updater from 2.0.0-beta.2 to 2.0.0-beta.3.

---
updated-dependencies:
- dependency-name: "@tauri-apps/plugin-updater"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:37:13 -07:00
3effb87f8e Bump react-router-dom from 6.22.3 to 6.23.1 (#2405)
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.22.3 to 6.23.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.23.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:36:57 -07:00
3f2f035a9b Bump three from 0.163.0 to 0.164.1 (#2406)
Bumps [three](https://github.com/mrdoob/three.js) from 0.163.0 to 0.164.1.
- [Release notes](https://github.com/mrdoob/three.js/releases)
- [Commits](https://github.com/mrdoob/three.js/commits)

---
updated-dependencies:
- dependency-name: three
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:36:47 -07:00
4735eaef8c Bump vitest from 1.5.0 to 1.6.0 (#2402)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v1.6.0/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 21:36:35 -07:00
69f8da058a add tests for min and max (#2420)
* add tests

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

* Update src/wasm-lib/kcl/src/std/math.rs

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>

* fmt

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

* add another

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2024-05-20 21:14:00 -07:00
93ebf13621 Wrapper for keybindings (codemirror and app) (#2421)
* start

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

* add hotkey wrapper

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>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-20 20:52:33 -07:00
20c4d44b8b Cut release v0.21.5 (#2418) 2024-05-21 10:35:10 +10:00
8ea8f80e32 Sort keys alphabetically in the Variables/Memory panel (#2417) 2024-05-20 17:28:51 -05:00
d73339fd8d Edit mode prep (#2370)
* remove edit mode

* small rename

* update with compat with old edit mode

* exit edit mode still needed

* add log to export
2024-05-21 05:55:34 +10:00
031b230690 Disable home logo link in the browser app (#2371)
* Disable logo link in browser, clean up menu components' organization

* Include the app name in Tauri as screenreader-only text

* Fix tsc issue in component test

* Add a playwright test to ensure logo is never a link in the browser

* Update broken component tests
2024-05-20 14:59:59 -04:00
1125d74f12 Update serde (#2415) 2024-05-20 18:01:48 +00:00
5c7a2822d0 Add some JSDocs comments to types, convert some existing comments. (#2363)
* Add some JSDocs comments to types, convert some existing comments.

* Add JSDoc comments to EngineCommandManager

* Add deprecation message to `lastArtifactMap`

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rerun CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-20 13:38:51 -04:00
d44b1f8e54 Fix code editor user input in older version of Safari (#2350)
Fix where code editor wasn't allowing code insertion in older versions of Safari.

Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-05-20 11:28:34 -04:00
c4ca69496b update deps (#2412)
* update deps

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-20 06:36:44 +00:00
f06de7f586 Bump proc-macro2 from 1.0.82 to 1.0.83 in /src/wasm-lib (#2409)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.82 to 1.0.83.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.82...1.0.83)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-05-19 22:08:21 -07:00
75c6ae6e66 sketch dies on exit XY sketch (#2397)
* sketch dies on exit XY sketch

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger ci

* fix test

* fix test

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-20 14:38:19 +10:00
48639d70db Bump anyhow from 1.0.83 to 1.0.86 in /src/wasm-lib (#2407)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.83 to 1.0.86.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.83...1.0.86)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-19 21:12:51 -07:00
c565d9670d Bump syn from 2.0.64 to 2.0.65 in /src/wasm-lib (#2410)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.64 to 2.0.65.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.64...2.0.65)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-19 21:12:15 -07:00
7bf5953299 Bump thiserror from 1.0.60 to 1.0.61 in /src/wasm-lib (#2411)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.60 to 1.0.61.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.60...1.0.61)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-19 21:05:36 -07:00
a9ab35e55f double-clicking a model file (obj, stl, etc) will auto generate a file with an import statement and open it (#2400)
* open model files and generate the content

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-20 00:45:09 +00:00
15418e98b0 missed a file (#2399)
updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-20 00:16:26 +00:00
20838bf618 actually make import samples run (#2398)
* actually make import samples run

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

* format

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-05-20 00:02:25 +00:00
acd52ab350 fix function variable panel issue (#2392)
* fix function variable panel issue

* fix test
2024-05-19 20:56:19 +10:00
75b9d2913f fix max std lib (#2391) 2024-05-19 16:42:22 +10:00
d92e6f6453 Bump toml from 0.8.12 to 0.8.13 in /src/wasm-lib (#2367)
Bumps [toml](https://github.com/toml-rs/toml) from 0.8.12 to 0.8.13.
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.12...toml-v0.8.13)

---
updated-dependencies:
- dependency-name: toml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-17 17:36:50 -07:00
c1a879837e Bump deps (#2385) 2024-05-17 21:06:16 +00:00
daacca500c Tell ts-rs to no worry about serde tags (#2387)
These build warnings are persistent and they're load-bearing to other
code.

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>
2024-05-17 16:46:42 -04:00
c1e8bb5288 Add "copy to clipboard" button to Variables pane (#2388) 2024-05-17 20:40:20 +00:00
8ca4166b08 Bump serde from 1.0.201 to 1.0.202 in /src/wasm-lib (#2368)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.201 to 1.0.202.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.201...v1.0.202)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-17 10:53:33 -07:00
4624f1c0ba Update tauri's Cargo.lock (#2381) 2024-05-17 17:19:50 +00:00
7ac6a3a4f2 Bump itertools from 0.12.1 to 0.13.0 in /src/wasm-lib (#2377)
Bumps [itertools](https://github.com/rust-itertools/itertools) from 0.12.1 to 0.13.0.
- [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-itertools/itertools/compare/v0.12.1...v0.13.0)

---
updated-dependencies:
- dependency-name: itertools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-17 09:09:23 -07:00
3cbf2b194a Bump syn from 2.0.63 to 2.0.64 in /src/wasm-lib (#2378)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.63 to 2.0.64.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.63...2.0.64)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-17 09:09:00 -07:00
44f06aa199 Cut release v0.21.4 (#2380) 2024-05-17 15:40:56 +00:00
1b878865b8 Set default extrude distance expression to something more sensible, like 5 (#2351)
* Set default extrude distance expression to something more sensible, like 5

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rerun CI

* run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* CI

* Use old 5 + 7 for highlight test it's touchy

* Same with sketch on face it seems to work better with 5 + 7 and that's fine

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-17 10:29:04 -04:00
3b840e9a80 Disable all pane resize handles except right (#2372)
* Disable all pane resize handles except right

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-05-16 22:30:47 -04:00
4a0811eec8 Fix CSS bug causing ProjectCard links to flicker (#2375)
on Microsoft desktop apps running old versions of Edge
2024-05-16 21:05:20 -04:00
125 changed files with 5950 additions and 1019 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,12 +278,11 @@ 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
The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend. The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend.
How to interpret failing playwright tests? How to interpret failing playwright tests?
If your tests fail, click through to the action and see that the tests failed on a line that includes `await page.getByTestId('loading').waitFor({ state: 'detached' })`, this means the test fail because the stream never started. It's you choice if you want to re-run the test, or ignore the failure. If your tests fail, click through to the action and see that the tests failed on a line that includes `await page.getByTestId('loading').waitFor({ state: 'detached' })`, this means the test fail because the stream never started. It's you choice if you want to re-run the test, or ignore the failure.
@ -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).

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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)

File diff suppressed because one or more lines are too long

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

@ -13,6 +13,7 @@ import {
} from './storageStates' } from './storageStates'
import * as TOML from '@iarna/toml' import * as TOML from '@iarna/toml'
import { Coords2d } from 'lang/std/sketch' import { Coords2d } from 'lang/std/sketch'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
/* /*
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
@ -347,6 +348,15 @@ test('if you use the format keyboard binding it formats your code', async ({
|> close(%)`) |> close(%)`)
}) })
test('ensure the Zoo logo is not a link in browser app', async ({ page }) => {
await page.setViewportSize({ width: 1000, height: 500 })
await page.goto('/')
const zooLogo = page.locator('[data-testid="app-logo"]')
// Make sure it's not a link
await expect(zooLogo).not.toHaveAttribute('href')
})
test('if you write invalid kcl you get inlined errors', async ({ page }) => { test('if you write invalid kcl you get inlined errors', async ({ page }) => {
const u = getUtils(page) const u = getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setViewportSize({ width: 1000, height: 500 })
@ -414,6 +424,80 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
}) })
test('error with 2 source ranges gets 2 diagnostics', async ({ page }) => {
const u = getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const length = .750
const width = 0.500
const height = 0.500
const dia = 4
fn squareHole = (l, w) => {
const squareHoleSketch = startSketchOn('XY')
|> startProfileAt([-width / 2, -length / 2], %)
|> lineTo([width / 2, -length / 2], %)
|> lineTo([width / 2, length / 2], %)
|> lineTo([-width / 2, length / 2], %)
|> close(%)
return squareHoleSketch
}
`
)
})
await page.setViewportSize({ width: 1000, height: 500 })
await page.goto('/')
const lspStartPromise = page.waitForEvent('console', async (message) => {
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
// but that doesn't seem to make it to the console for macos/safari :(
if (message.text().includes('start kcl lsp')) {
await new Promise((resolve) => setTimeout(resolve, 200))
return true
}
return false
})
await page.goto('/')
await u.waitForAuthSkipAppStart()
await lspStartPromise
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
// check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Click on the bottom of the code editor to add a new line
await page.click('.cm-content')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('Enter')
await page.keyboard.type(`const extrusion = startSketchOn('XY')
|> circle([0, 0], dia/2, %)
|> hole(squareHole(length, width, height), %)
|> extrude(height, %)`)
// error in gutter
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
await page.hover('.cm-lint-marker-error:first-child')
await expect(page.getByText('Expected 2 arguments, got 3')).toBeVisible()
// Make sure there are two diagnostics
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
})
test('if your kcl gets an error from the engine it is inlined', async ({ test('if your kcl gets an error from the engine it is inlined', async ({
page, page,
}) => { }) => {
@ -636,8 +720,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')
@ -765,6 +849,130 @@ test('Project settings can be set and override user settings', async ({
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light') await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
}) })
test('Project settings can be opened with keybinding from the editor', async ({
page,
}) => {
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })
// Put the cursor in the editor
await page.click('.cm-content')
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('dark')
// Roll back to default "system" theme
await page
.getByText(
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
.hover()
await page
.getByRole('button', {
name: 'Roll back theme ; Has tooltip: Roll back to match default',
})
.click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
})
test('Project and user settings can be reset', async ({ page }) => {
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })
// Put the cursor in the editor
await page.click('.cm-content')
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Set the user theme to light.
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" as a user default`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
})
test('Click through each onboarding step', async ({ page }) => { test('Click through each onboarding step', async ({ page }) => {
const u = getUtils(page) const u = getUtils(page)
@ -1082,6 +1290,51 @@ test.describe('Command bar tests', () => {
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`) await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
}) })
test('Command bar keybinding works from code editor and can change a setting', async ({
page,
}) => {
// Brief boilerplate
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
let cmdSearchBar = page.getByPlaceholder('Search commands')
// Put the cursor in the code editor
await page.click('.cm-content')
// Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('Meta+K')
await expect(cmdSearchBar).toBeVisible()
await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar
await page.keyboard.type('theme')
const themeOption = page.getByRole('option', {
name: 'Settings · app · theme',
})
await expect(themeOption).toBeVisible()
await themeOption.click()
const themeInput = page.getByPlaceholder('Select an option')
await expect(themeInput).toBeVisible()
await expect(themeInput).toBeFocused()
// Select dark theme
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await expect(page.getByRole('option', { name: 'system' })).toHaveAttribute(
'data-headlessui-state',
'active'
)
await page.keyboard.press('Enter')
// Check the toast appeared
await expect(
page.getByText(`Set theme to "system" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
})
test('Can extrude from the command bar', async ({ page }) => { test('Can extrude from the command bar', async ({ page }) => {
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
@ -1145,7 +1398,7 @@ test.describe('Command bar tests', () => {
// Assert we're back on the distance step // Assert we're back on the distance step
await expect( await expect(
page.getByRole('button', { name: 'Distance 12', exact: false }) page.getByRole('button', { name: 'Distance 5', exact: false })
).toBeDisabled() ).toBeDisabled()
await continueButton.click() await continueButton.click()
@ -1156,7 +1409,7 @@ test.describe('Command bar tests', () => {
// Unfortunately this indentation seems to matter for the test // Unfortunately this indentation seems to matter for the test
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`const distance = sqrt(20) `const distance = sqrt(20)
const distance001 = 5 + 7 const distance001 = ${KCL_DEFAULT_LENGTH}
const part001 = startSketchOn('-XZ') const part001 = startSketchOn('-XZ')
|> startProfileAt([-6.95, 10.98], %) |> startProfileAt([-6.95, 10.98], %)
|> line([25.1, 0.41], %) |> line([25.1, 0.41], %)
@ -1353,7 +1606,7 @@ test('ProgramMemory can be serialised', async ({ page }) => {
test('Hovering over 3d features highlights code', async ({ page }) => { test('Hovering over 3d features highlights code', async ({ page }) => {
const u = getUtils(page) const u = getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`const part001 = startSketchOn('-XZ') `const part001 = startSketchOn('-XZ')
@ -1378,7 +1631,7 @@ test('Hovering over 3d features highlights code', async ({ page }) => {
|> extrude(5 + 7, %) |> extrude(5 + 7, %)
` `
) )
}) }, KCL_DEFAULT_LENGTH)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setViewportSize({ width: 1000, height: 500 })
await page.goto('/') await page.goto('/')
await u.waitForAuthSkipAppStart() await u.waitForAuthSkipAppStart()
@ -1957,6 +2210,6 @@ test('Extrude from command bar selects extrude line after', async ({
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-activeLine')).toHaveText( await expect(page.locator('.cm-activeLine')).toHaveText(
` |> extrude(5 + 7, %)` ` |> extrude(${KCL_DEFAULT_LENGTH}, %)`
) )
}) })

View File

@ -4,7 +4,7 @@ import { getUtils } from './test-utils'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { spawn } from 'child_process' import { spawn } from 'child_process'
import { APP_NAME } from 'lib/constants' import { APP_NAME, KCL_DEFAULT_LENGTH } from 'lib/constants'
import JSZip from 'jszip' import JSZip from 'jszip'
import path from 'path' import path from 'path'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates' import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates'
@ -273,6 +273,8 @@ const part001 = startSketchOn('-XZ')
for (let { modelPath, imagePath, outputType } of exportLocations) { for (let { modelPath, imagePath, outputType } of exportLocations) {
// May change depending on the file being dealt with // May change depending on the file being dealt with
let cliCommand = `export ZOO_TOKEN=${secrets.snapshottoken} && zoo file snapshot --output-format=png --src-format=${outputType} ${modelPath} ${imagePath}` let cliCommand = `export ZOO_TOKEN=${secrets.snapshottoken} && zoo file snapshot --output-format=png --src-format=${outputType} ${modelPath} ${imagePath}`
const fileSize = (await fsp.stat(modelPath)).size
console.log(`Size of the file at ${modelPath}: ${fileSize} bytes`)
const parentPath = path.dirname(modelPath) const parentPath = path.dirname(modelPath)
@ -718,7 +720,7 @@ test.describe('Client side scene scale should match engine scale', () => {
test('Sketch on face with none z-up', async ({ page, context }) => { test('Sketch on face with none z-up', async ({ page, context }) => {
const u = getUtils(page) const u = getUtils(page)
await context.addInitScript(async () => { await context.addInitScript(async (KCL_DEFAULT_LENGTH) => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`const part001 = startSketchOn('-XZ') `const part001 = startSketchOn('-XZ')
@ -726,16 +728,16 @@ test('Sketch on face with none z-up', async ({ page, context }) => {
|> line([9.31, 10.55], %, 'seg01') |> line([9.31, 10.55], %, 'seg01')
|> line([11.91, -10.42], %) |> line([11.91, -10.42], %)
|> close(%) |> close(%)
|> extrude(5 + 7, %) |> extrude(${KCL_DEFAULT_LENGTH}, %)
const part002 = startSketchOn(part001, 'seg01') const part002 = startSketchOn(part001, 'seg01')
|> startProfileAt([8, 8], %) |> startProfileAt([8, 8], %)
|> line([4.68, 3.05], %) |> line([4.68, 3.05], %)
|> line([0, -7.79], %, 'seg02') |> line([0, -7.79], %, 'seg02')
|> close(%) |> close(%)
|> extrude(5 + 7, %) |> extrude(${KCL_DEFAULT_LENGTH}, %)
` `
) )
}) }, KCL_DEFAULT_LENGTH)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/') await page.goto('/')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -1,6 +1,6 @@
{ {
"name": "untitled-app", "name": "untitled-app",
"version": "0.21.3", "version": "0.21.6",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.16.0", "@codemirror/autocomplete": "^6.16.0",
@ -17,12 +17,12 @@
"@replit/codemirror-interact": "^6.3.1", "@replit/codemirror-interact": "^6.3.1",
"@tauri-apps/api": "2.0.0-beta.8", "@tauri-apps/api": "2.0.0-beta.8",
"@tauri-apps/plugin-dialog": "^2.0.0-beta.2", "@tauri-apps/plugin-dialog": "^2.0.0-beta.2",
"@tauri-apps/plugin-fs": "^2.0.0-beta.2", "@tauri-apps/plugin-fs": "^2.0.0-beta.3",
"@tauri-apps/plugin-http": "^2.0.0-beta.2", "@tauri-apps/plugin-http": "^2.0.0-beta.2",
"@tauri-apps/plugin-os": "^2.0.0-beta.2", "@tauri-apps/plugin-os": "^2.0.0-beta.2",
"@tauri-apps/plugin-process": "^2.0.0-beta.2", "@tauri-apps/plugin-process": "^2.0.0-beta.2",
"@tauri-apps/plugin-shell": "^2.0.0-beta.2", "@tauri-apps/plugin-shell": "^2.0.0-beta.2",
"@tauri-apps/plugin-updater": "^2.0.0-beta.2", "@tauri-apps/plugin-updater": "^2.0.0-beta.3",
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2", "@testing-library/react": "^15.0.2",
"@testing-library/user-event": "^14.5.2", "@testing-library/user-event": "^14.5.2",
@ -52,15 +52,15 @@
"react-json-view": "^1.21.3", "react-json-view": "^1.21.3",
"react-modal": "^3.16.1", "react-modal": "^3.16.1",
"react-modal-promise": "^1.0.2", "react-modal-promise": "^1.0.2",
"react-router-dom": "^6.22.3", "react-router-dom": "^6.23.1",
"sketch-helpers": "^0.0.4", "sketch-helpers": "^0.0.4",
"swr": "^2.2.5", "swr": "^2.2.5",
"three": "^0.163.0", "three": "^0.164.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"ua-parser-js": "^1.0.37", "ua-parser-js": "^1.0.37",
"uuid": "^9.0.1", "uuid": "^9.0.1",
"vitest": "^1.5.0", "vitest": "^1.6.0",
"vscode-jsonrpc": "^8.1.0", "vscode-jsonrpc": "^8.1.0",
"vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-protocol": "^3.17.5",
"wasm-pack": "^0.12.1", "wasm-pack": "^0.12.1",

207
src-tauri/Cargo.lock generated
View File

@ -169,9 +169,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.83" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
dependencies = [ dependencies = [
"backtrace", "backtrace",
] ]
@ -199,7 +199,7 @@ dependencies = [
"tauri-plugin-shell", "tauri-plugin-shell",
"tauri-plugin-updater", "tauri-plugin-updater",
"tokio", "tokio",
"toml 0.8.12", "toml 0.8.13",
"url", "url",
] ]
@ -212,6 +212,15 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.4" version = "0.7.4"
@ -334,7 +343,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -369,7 +378,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -415,7 +424,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -564,7 +573,7 @@ dependencies = [
"proc-macro-crate 3.1.0", "proc-macro-crate 3.1.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"syn_derive", "syn_derive",
] ]
@ -756,7 +765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719"
dependencies = [ dependencies = [
"serde", "serde",
"toml 0.8.12", "toml 0.8.13",
] ]
[[package]] [[package]]
@ -873,7 +882,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1075,7 +1084,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1085,7 +1094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1109,7 +1118,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.10.0", "strsim 0.10.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1120,7 +1129,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1167,7 +1176,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"synstructure", "synstructure",
] ]
@ -1204,7 +1213,18 @@ dependencies = [
"regex", "regex",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.63", "syn 2.0.65",
]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
] ]
[[package]] [[package]]
@ -1258,6 +1278,17 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "displaydoc"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
]
[[package]] [[package]]
name = "dlib" name = "dlib"
version = "0.5.2" version = "0.5.2"
@ -1287,7 +1318,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1341,7 +1372,7 @@ dependencies = [
"cc", "cc",
"memchr", "memchr",
"rustc_version", "rustc_version",
"toml 0.8.12", "toml 0.8.13",
"vswhom", "vswhom",
"winreg 0.52.0", "winreg 0.52.0",
] ]
@ -1385,7 +1416,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1536,7 +1567,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1652,7 +1683,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1928,7 +1959,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1956,7 +1987,7 @@ dependencies = [
"inflections", "inflections",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2031,7 +2062,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2569,7 +2600,7 @@ dependencies = [
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
"toml 0.8.12", "toml 0.8.13",
"tower-lsp", "tower-lsp",
"ts-rs", "ts-rs",
"url", "url",
@ -2579,7 +2610,7 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"winnow 0.5.40", "winnow 0.5.40",
"zip", "zip 1.3.0",
] ]
[[package]] [[package]]
@ -2640,7 +2671,7 @@ checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3362,7 +3393,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.7.5", "regex-syntax 0.7.5",
"structmeta 0.2.0", "structmeta 0.2.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3376,7 +3407,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.8.3", "regex-syntax 0.8.3",
"structmeta 0.3.0", "structmeta 0.3.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3518,7 +3549,7 @@ dependencies = [
"phf_shared 0.11.2", "phf_shared 0.11.2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3586,7 +3617,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4424,7 +4455,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde_derive_internals", "serde_derive_internals",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4509,9 +4540,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.201" version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -4527,13 +4558,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.201" version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4544,7 +4575,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4577,14 +4608,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "0.6.5" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -4598,7 +4629,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4640,7 +4671,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4908,7 +4939,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive 0.2.0", "structmeta-derive 0.2.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4920,7 +4951,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive 0.3.0", "structmeta-derive 0.3.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4931,7 +4962,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4942,7 +4973,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4964,7 +4995,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4997,9 +5028,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.63" version = "2.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -5015,7 +5046,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -5032,7 +5063,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -5074,7 +5105,7 @@ dependencies = [
"cfg-expr", "cfg-expr",
"heck 0.5.0", "heck 0.5.0",
"pkg-config", "pkg-config",
"toml 0.8.12", "toml 0.8.13",
"version-compare", "version-compare",
] ]
@ -5227,7 +5258,7 @@ dependencies = [
"serde_json", "serde_json",
"tauri-utils", "tauri-utils",
"tauri-winres", "tauri-winres",
"toml 0.8.12", "toml 0.8.13",
"walkdir", "walkdir",
] ]
@ -5249,7 +5280,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"syn 2.0.63", "syn 2.0.65",
"tauri-utils", "tauri-utils",
"thiserror", "thiserror",
"time", "time",
@ -5267,7 +5298,7 @@ dependencies = [
"heck 0.4.1", "heck 0.4.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"tauri-codegen", "tauri-codegen",
"tauri-utils", "tauri-utils",
] ]
@ -5285,7 +5316,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"tauri-utils", "tauri-utils",
"toml 0.8.12", "toml 0.8.13",
"walkdir", "walkdir",
] ]
@ -5471,7 +5502,7 @@ dependencies = [
"tokio", "tokio",
"url", "url",
"windows-sys 0.52.0", "windows-sys 0.52.0",
"zip", "zip 0.6.6",
] ]
[[package]] [[package]]
@ -5546,7 +5577,7 @@ dependencies = [
"serde_with", "serde_with",
"swift-rs", "swift-rs",
"thiserror", "thiserror",
"toml 0.8.12", "toml 0.8.13",
"url", "url",
"urlpattern", "urlpattern",
"walkdir", "walkdir",
@ -5602,22 +5633,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.60" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.60" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -5706,7 +5737,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -5774,21 +5805,21 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.8.12" version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned", "serde_spanned",
"toml_datetime", "toml_datetime",
"toml_edit 0.22.12", "toml_edit 0.22.13",
] ]
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.5" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -5830,9 +5861,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.22.12" version = "0.22.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c"
dependencies = [ dependencies = [
"indexmap 2.2.6", "indexmap 2.2.6",
"serde", "serde",
@ -5895,7 +5926,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -5924,7 +5955,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -6048,7 +6079,7 @@ dependencies = [
"Inflector", "Inflector",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"termcolor", "termcolor",
] ]
@ -6261,7 +6292,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -6360,7 +6391,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6394,7 +6425,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6535,7 +6566,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -6641,7 +6672,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -6652,7 +6683,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -7094,7 +7125,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -7123,6 +7154,20 @@ dependencies = [
"zstd", "zstd",
] ]
[[package]]
name = "zip"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f4a27345eb6f7aa7bd015ba7eb4175fa4e1b462a29874b779e0bbcf96c6ac7"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
"indexmap 2.2.6",
"thiserror",
]
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.11.2+zstd.1.5.2" version = "0.11.2+zstd.1.5.2"

View File

@ -121,11 +121,8 @@ async fn write_app_settings_file(app: tauri::AppHandle, configuration: Configura
Ok(()) Ok(())
} }
async fn get_project_settings_file_path( async fn get_project_settings_file_path(project_path: &str) -> Result<PathBuf, InvokeError> {
app_settings: Configuration, let project_dir = std::path::Path::new(project_path);
project_name: &str,
) -> Result<PathBuf, InvokeError> {
let project_dir = app_settings.settings.project.directory.join(project_name);
if !project_dir.exists() { if !project_dir.exists() {
tokio::fs::create_dir_all(&project_dir) tokio::fs::create_dir_all(&project_dir)
@ -137,11 +134,8 @@ async fn get_project_settings_file_path(
} }
#[tauri::command] #[tauri::command]
async fn read_project_settings_file( async fn read_project_settings_file(project_path: &str) -> Result<ProjectConfiguration, InvokeError> {
app_settings: Configuration, let settings_path = get_project_settings_file_path(project_path).await?;
project_name: &str,
) -> Result<ProjectConfiguration, InvokeError> {
let settings_path = get_project_settings_file_path(app_settings, project_name).await?;
// Check if this file exists. // Check if this file exists.
if !settings_path.exists() { if !settings_path.exists() {
@ -159,11 +153,10 @@ async fn read_project_settings_file(
#[tauri::command] #[tauri::command]
async fn write_project_settings_file( async fn write_project_settings_file(
app_settings: Configuration, project_path: &str,
project_name: &str,
configuration: ProjectConfiguration, configuration: ProjectConfiguration,
) -> Result<(), InvokeError> { ) -> Result<(), InvokeError> {
let settings_path = get_project_settings_file_path(app_settings, project_name).await?; let settings_path = get_project_settings_file_path(project_path).await?;
let contents = toml::to_string_pretty(&configuration).map_err(|e| InvokeError::from_anyhow(e.into()))?; let contents = toml::to_string_pretty(&configuration).map_err(|e| InvokeError::from_anyhow(e.into()))?;
tokio::fs::write(settings_path, contents.as_bytes()) tokio::fs::write(settings_path, contents.as_bytes())
.await .await

View File

@ -74,5 +74,5 @@
} }
}, },
"productName": "Zoo Modeling App", "productName": "Zoo Modeling App",
"version": "0.21.3" "version": "0.21.6"
} }

View File

@ -23,6 +23,7 @@ import { useRefreshSettings } from 'hooks/useRefreshSettings'
import { ModelingSidebar } from 'components/ModelingSidebar/ModelingSidebar' import { ModelingSidebar } from 'components/ModelingSidebar/ModelingSidebar'
import { LowerRightControls } from 'components/LowerRightControls' import { LowerRightControls } from 'components/LowerRightControls'
import ModalContainer from 'react-modal-promise' import ModalContainer from 'react-modal-promise'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
export function App() { export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS') useRefreshSettings(paths.FILE + 'SETTINGS')
@ -63,8 +64,8 @@ export function App() {
useHotkeys('backspace', (e) => { useHotkeys('backspace', (e) => {
e.preventDefault() e.preventDefault()
}) })
useHotkeys( useHotkeyWrapper(
isTauri() ? 'mod + ,' : 'shift + mod + ,', [isTauri() ? 'mod + ,' : 'shift + mod + ,'],
() => navigate(filePath + paths.SETTINGS), () => navigate(filePath + paths.SETTINGS),
{ {
splitKey: '|', splitKey: '|',

View File

@ -34,7 +34,7 @@ export const AppHeader = ({
} }
> >
<ProjectSidebarMenu <ProjectSidebarMenu
renderAsLink={!enableMenu} enableMenu={enableMenu}
project={project?.project} project={project?.project}
file={project?.file} file={project?.file}
/> />

View File

@ -1,11 +1,11 @@
import { Dialog, Popover, Transition } from '@headlessui/react' import { Dialog, Popover, Transition } from '@headlessui/react'
import { Fragment, useEffect } from 'react' import { Fragment, useEffect } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { useCommandsContext } from 'hooks/useCommandsContext' import { useCommandsContext } from 'hooks/useCommandsContext'
import CommandBarArgument from './CommandBarArgument' import CommandBarArgument from './CommandBarArgument'
import CommandComboBox from '../CommandComboBox' import CommandComboBox from '../CommandComboBox'
import CommandBarReview from './CommandBarReview' import CommandBarReview from './CommandBarReview'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
export const CommandBar = () => { export const CommandBar = () => {
const { pathname } = useLocation() const { pathname } = useLocation()
@ -22,7 +22,7 @@ export const CommandBar = () => {
}, [pathname]) }, [pathname])
// Hook up keyboard shortcuts // Hook up keyboard shortcuts
useHotkeys(['mod+k', 'mod+/'], () => { useHotkeyWrapper(['mod+k', 'mod+/'], () => {
if (commandBarState.context.commands.length === 0) return if (commandBarState.context.commands.length === 0) return
if (commandBarState.matches('Closed')) { if (commandBarState.matches('Closed')) {
commandBarSend({ type: 'Open' }) commandBarSend({ type: 'Open' })

View File

@ -56,7 +56,7 @@ function CommandBarSelectionInput({
// In future the engine's edit mode will go away and this will be handled differently. // In future the engine's edit mode will go away and this will be handled differently.
useEffect(() => { useEffect(() => {
kclManager.exitEditMode() kclManager.exitEditMode()
return () => kclManager.enterEditMode() return () => kclManager.defaultSelectionFilter()
}, []) }, [])
// Fast-forward through this arg if it's marked as skippable // Fast-forward through this arg if it's marked as skippable

View File

@ -8,7 +8,6 @@ import { Dialog, Disclosure } from '@headlessui/react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons' import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { useFileContext } from 'hooks/useFileContext' import { useFileContext } from 'hooks/useFileContext'
import { useHotkeys } from 'react-hotkeys-hook'
import styles from './FileTree.module.css' import styles from './FileTree.module.css'
import { sortProject } from 'lib/tauriFS' import { sortProject } from 'lib/tauriFS'
import { FILE_EXT } from 'lib/constants' import { FILE_EXT } from 'lib/constants'
@ -16,6 +15,7 @@ import { CustomIcon } from './CustomIcon'
import { codeManager, kclManager } from 'lib/singletons' import { codeManager, kclManager } from 'lib/singletons'
import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus' import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus'
import { useLspContext } from './LspProvider' import { useLspContext } from './LspProvider'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
function getIndentationCSS(level: number) { function getIndentationCSS(level: number) {
return `calc(1rem * ${level + 1})` return `calc(1rem * ${level + 1})`
@ -333,8 +333,8 @@ export const FileTreeMenu = () => {
send({ type: 'Create file', data: { name: '', makeDir: true } }) send({ type: 'Create file', data: { name: '', makeDir: true } })
} }
useHotkeys('meta + n', createFile) useHotkeyWrapper(['meta + n'], createFile)
useHotkeys('meta + shift + n', createFolder) useHotkeyWrapper(['meta + shift + n'], createFolder)
return ( return (
<> <>

View File

@ -22,8 +22,7 @@ import {
LspWorker, LspWorker,
} from 'editor/plugins/lsp/types' } from 'editor/plugins/lsp/types'
import { wasmUrl } from 'lang/wasm' import { wasmUrl } from 'lang/wasm'
import { PROJECT_ENTRYPOINT } from 'lib/constants'
const DEFAULT_FILE_NAME: string = 'main.kcl'
function getWorkspaceFolders(): LSP.WorkspaceFolder[] { function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
return [] return []
@ -137,7 +136,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (isKclLspServerReady && !TEST && kclLspClient) { if (isKclLspServerReady && !TEST && kclLspClient) {
// Set up the lsp plugin. // Set up the lsp plugin.
const lsp = kclLanguage({ const lsp = kclLanguage({
documentUri: `file:///${DEFAULT_FILE_NAME}`, documentUri: `file:///${PROJECT_ENTRYPOINT}`,
workspaceFolders: getWorkspaceFolders(), workspaceFolders: getWorkspaceFolders(),
client: kclLspClient, client: kclLspClient,
}) })
@ -211,7 +210,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (isCopilotLspServerReady && !TEST && copilotLspClient) { if (isCopilotLspServerReady && !TEST && copilotLspClient) {
// Set up the lsp plugin. // Set up the lsp plugin.
const lsp = copilotPlugin({ const lsp = copilotPlugin({
documentUri: `file:///${DEFAULT_FILE_NAME}`, documentUri: `file:///${PROJECT_ENTRYPOINT}`,
workspaceFolders: getWorkspaceFolders(), workspaceFolders: getWorkspaceFolders(),
client: copilotLspClient, client: copilotLspClient,
allowHTMLContent: true, allowHTMLContent: true,
@ -236,7 +235,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
redirect: boolean redirect: boolean
) => { ) => {
const currentFilePath = projectBasename( const currentFilePath = projectBasename(
file?.path || DEFAULT_FILE_NAME, file?.path || PROJECT_ENTRYPOINT,
projectPath || '' projectPath || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {
@ -267,7 +266,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (file) { if (file) {
// Send that the file was opened. // Send that the file was opened.
const filename = projectBasename( const filename = projectBasename(
file?.path || DEFAULT_FILE_NAME, file?.path || PROJECT_ENTRYPOINT,
project?.path || '' project?.path || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {
@ -285,7 +284,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const onFileOpen = (filePath: string | null, projectPath: string | null) => { const onFileOpen = (filePath: string | null, projectPath: string | null) => {
const currentFilePath = projectBasename( const currentFilePath = projectBasename(
filePath || DEFAULT_FILE_NAME, filePath || PROJECT_ENTRYPOINT,
projectPath || '' projectPath || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {
@ -302,7 +301,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const onFileClose = (filePath: string | null, projectPath: string | null) => { const onFileClose = (filePath: string | null, projectPath: string | null) => {
const currentFilePath = projectBasename( const currentFilePath = projectBasename(
filePath || DEFAULT_FILE_NAME, filePath || PROJECT_ENTRYPOINT,
projectPath || '' projectPath || ''
) )
lspClients.forEach((lspClient) => { lspClients.forEach((lspClient) => {

View File

@ -55,9 +55,9 @@ import { Models } from '@kittycad/lib/dist/types/src'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { EditorSelection } from '@uiw/react-codemirror' import { EditorSelection } from '@uiw/react-codemirror'
import { CoreDumpManager } from 'lib/coredump' import { CoreDumpManager } from 'lib/coredump'
import { useHotkeys } from 'react-hotkeys-hook'
import { useSearchParams } from 'react-router-dom' import { useSearchParams } from 'react-router-dom'
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls' import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T> state: StateFrom<T>
@ -103,7 +103,7 @@ export const ModelingMachineProvider = ({
htmlRef, htmlRef,
token token
) )
useHotkeys('meta + shift + .', () => coreDump(coreDumpManager, true)) useHotkeyWrapper(['meta + shift + .'], () => coreDump(coreDumpManager, true))
// Settings machine setup // Settings machine setup
// const retrievedSettings = useRef( // const retrievedSettings = useRef(

View File

@ -36,10 +36,6 @@ import {
import interact from '@replit/codemirror-interact' import interact from '@replit/codemirror-interact'
import { kclManager, editorManager, codeManager } from 'lib/singletons' import { kclManager, editorManager, codeManager } from 'lib/singletons'
import { useHotkeys } from 'react-hotkeys-hook' import { useHotkeys } from 'react-hotkeys-hook'
import { isTauri } from 'lib/isTauri'
import { useNavigate } from 'react-router-dom'
import { paths } from 'lib/paths'
import makeUrlPathRelative from 'lib/makeUrlPathRelative'
import { useLspContext } from 'components/LspProvider' import { useLspContext } from 'components/LspProvider'
import { Prec, EditorState, Extension } from '@codemirror/state' import { Prec, EditorState, Extension } from '@codemirror/state'
import { import {
@ -67,7 +63,6 @@ export const KclEditorPane = () => {
? getSystemTheme() ? getSystemTheme()
: context.app.theme.current : context.app.theme.current
const { copilotLSP, kclLSP } = useLspContext() const { copilotLSP, kclLSP } = useLspContext()
const navigate = useNavigate()
useEffect(() => { useEffect(() => {
if (typeof window === 'undefined') return if (typeof window === 'undefined') return
@ -76,6 +71,8 @@ export const KclEditorPane = () => {
return () => window.removeEventListener('online', onlineCallback) return () => window.removeEventListener('online', onlineCallback)
}, []) }, [])
// Since these already exist in the editor, we don't need to define them
// with the wrapper.
useHotkeys('mod+z', (e) => { useHotkeys('mod+z', (e) => {
e.preventDefault() e.preventDefault()
editorManager.undo() editorManager.undo()
@ -87,6 +84,7 @@ export const KclEditorPane = () => {
const textWrapping = context.textEditor.textWrapping const textWrapping = context.textEditor.textWrapping
const cursorBlinking = context.textEditor.blinkingCursor const cursorBlinking = context.textEditor.blinkingCursor
const codeMirrorHotkeys = codeManager.getCodemirrorHotkeys()
const editorExtensions = useMemo(() => { const editorExtensions = useMemo(() => {
const extensions = [ const extensions = [
@ -106,20 +104,7 @@ export const KclEditorPane = () => {
...completionKeymap, ...completionKeymap,
...lintKeymap, ...lintKeymap,
indentWithTab, indentWithTab,
{ ...codeMirrorHotkeys,
key: 'Meta-k',
run: () => {
editorManager.commandBarSend({ type: 'Open' })
return false
},
},
{
key: isTauri() ? 'Meta-,' : 'Meta-Shift-,',
run: () => {
navigate(makeUrlPathRelative(paths.SETTINGS))
return false
},
},
{ {
key: editorShortcutMeta.convertToVariable.codeMirror, key: editorShortcutMeta.convertToVariable.codeMirror,
run: () => { run: () => {
@ -188,7 +173,13 @@ export const KclEditorPane = () => {
} }
return extensions return extensions
}, [kclLSP, copilotLSP, textWrapping.current, cursorBlinking.current]) }, [
kclLSP,
copilotLSP,
textWrapping.current,
cursorBlinking.current,
codeMirrorHotkeys,
])
const initialCode = useRef(codeManager.code) const initialCode = useRef(codeManager.code)

View File

@ -38,7 +38,7 @@ describe('processMemory', () => {
expect(output.otherVar).toEqual(3) expect(output.otherVar).toEqual(3)
expect(output).toEqual({ expect(output).toEqual({
myVar: 5, myVar: 5,
myFn: undefined, myFn: '__function(a)__',
otherVar: 3, otherVar: 3,
theExtrude: [ theExtrude: [
{ {

View File

@ -3,6 +3,43 @@ import { useMemo } from 'react'
import { ProgramMemory, Path, ExtrudeSurface } from 'lang/wasm' import { ProgramMemory, Path, ExtrudeSurface } from 'lang/wasm'
import { useKclContext } from 'lang/KclProvider' import { useKclContext } from 'lang/KclProvider'
import { useResolvedTheme } from 'hooks/useResolvedTheme' import { useResolvedTheme } from 'hooks/useResolvedTheme'
import { ActionButton } from 'components/ActionButton'
import toast from 'react-hot-toast'
import Tooltip from 'components/Tooltip'
export const MemoryPaneMenu = () => {
const { programMemory } = useKclContext()
function copyProgramMemoryToClipboard() {
if (globalThis && 'navigator' in globalThis) {
try {
navigator.clipboard.writeText(JSON.stringify(programMemory))
toast.success('Program memory copied to clipboard')
} catch (e) {
toast.error('Failed to copy program memory to clipboard')
}
}
}
return (
<>
<ActionButton
Element="button"
iconStart={{
icon: 'clipboardPlus',
iconClassName: '!text-current',
bgClassName: 'bg-transparent',
}}
className="!p-0 !bg-transparent hover:text-primary border-transparent hover:border-primary !outline-none"
onClick={copyProgramMemoryToClipboard}
>
<Tooltip position="bottom-right" delay={750}>
Copy to clipboard
</Tooltip>
</ActionButton>
</>
)
}
export const MemoryPane = () => { export const MemoryPane = () => {
const theme = useResolvedTheme() const theme = useResolvedTheme()
@ -24,6 +61,7 @@ export const MemoryPane = () => {
displayObjectSize={true} displayObjectSize={true}
indentWidth={2} indentWidth={2}
quotesOnKeys={false} quotesOnKeys={false}
sortKeys={true}
name={false} name={false}
theme={theme === 'light' ? 'rjv-default' : 'monokai'} theme={theme === 'light' ? 'rjv-default' : 'monokai'}
/> />
@ -46,6 +84,10 @@ export const processMemory = (programMemory: ProgramMemory) => {
processedMemory[key] = val.value.map(({ ...rest }: ExtrudeSurface) => { processedMemory[key] = val.value.map(({ ...rest }: ExtrudeSurface) => {
return rest return rest
}) })
} else if ((val.type as any) === 'Function') {
processedMemory[key] = `__function(${(val as any)?.expression?.params
?.map?.(({ identifier }: any) => identifier?.name || '')
.join(', ')})__`
} else { } else {
processedMemory[key] = val.value processedMemory[key] = val.value
} }

View File

@ -10,7 +10,7 @@ import { KclEditorMenu } from 'components/ModelingSidebar/ModelingPanes/KclEdito
import { CustomIconName } from 'components/CustomIcon' import { CustomIconName } from 'components/CustomIcon'
import { KclEditorPane } from 'components/ModelingSidebar/ModelingPanes/KclEditorPane' import { KclEditorPane } from 'components/ModelingSidebar/ModelingPanes/KclEditorPane'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import { MemoryPane } from './MemoryPane' import { MemoryPane, MemoryPaneMenu } from './MemoryPane'
import { KclErrorsPane, LogsPane } from './LoggingPanes' import { KclErrorsPane, LogsPane } from './LoggingPanes'
import { DebugPane } from './DebugPane' import { DebugPane } from './DebugPane'
import { FileTreeInner, FileTreeMenu } from 'components/FileTree' import { FileTreeInner, FileTreeMenu } from 'components/FileTree'
@ -61,6 +61,7 @@ export const bottomPanes: SidebarPane[] = [
title: 'Variables', title: 'Variables',
icon: faSquareRootVariable, icon: faSquareRootVariable,
Content: MemoryPane, Content: MemoryPane,
Menu: MemoryPaneMenu,
keybinding: 'shift + v', keybinding: 'shift + v',
}, },
{ {

View File

@ -47,6 +47,13 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
right: right:
(openPanes.length === 0 ? 'hidden ' : 'block ') + (openPanes.length === 0 ? 'hidden ' : 'block ') +
'translate-x-1/2 hover:bg-chalkboard-10 hover:dark:bg-chalkboard-110 bg-transparent transition-colors duration-75 transition-ease-out delay-100 ', 'translate-x-1/2 hover:bg-chalkboard-10 hover:dark:bg-chalkboard-110 bg-transparent transition-colors duration-75 transition-ease-out delay-100 ',
left: 'hidden',
top: 'hidden',
topLeft: 'hidden',
topRight: 'hidden',
bottom: 'hidden',
bottomLeft: 'hidden',
bottomRight: 'hidden',
}} }}
> >
<div className={styles.grid + ' flex-1'}> <div className={styles.grid + ' flex-1'}>

View File

@ -70,9 +70,9 @@ function ProjectCard({
className="group relative min-h-[5em] p-1 rounded-sm border border-chalkboard-20 dark:border-chalkboard-80 hover:!border-primary" className="group relative min-h-[5em] p-1 rounded-sm border border-chalkboard-20 dark:border-chalkboard-80 hover:!border-primary"
> >
{isEditing ? ( {isEditing ? (
<form onSubmit={handleSave} className="flex gap-2 items-center"> <form onSubmit={handleSave} className="flex items-center gap-2">
<input <input
className="dark:bg-chalkboard-80 dark:border-chalkboard-40 min-w-0 p-1 focus:outline-none" className="min-w-0 p-1 dark:bg-chalkboard-80 dark:border-chalkboard-40 focus:outline-none"
type="text" type="text"
id="newProjectName" id="newProjectName"
name="newProjectName" name="newProjectName"
@ -81,7 +81,7 @@ function ProjectCard({
defaultValue={project.name} defaultValue={project.name}
ref={inputRef} ref={inputRef}
/> />
<div className="flex gap-1 items-center"> <div className="flex items-center gap-1">
<ActionButton <ActionButton
Element="button" Element="button"
type="submit" type="submit"
@ -117,78 +117,76 @@ function ProjectCard({
</form> </form>
) : ( ) : (
<> <>
<div className="p-1 flex flex-col h-full gap-2"> <Link
<Link className="relative z-0 flex flex-col h-full gap-2 p-1 !no-underline !text-chalkboard-110 dark:!text-chalkboard-10"
className="flex-1 !no-underline !text-chalkboard-110 dark:!text-chalkboard-10 after:content-[''] after:absolute after:inset-0" to={`${paths.FILE}/${encodeURIComponent(project.default_file)}`}
to={`${paths.FILE}/${encodeURIComponent(project.path)}`} data-testid="project-link"
data-testid="project-link" >
> <div className="flex-1">{project.name?.replace(FILE_EXT, '')}</div>
{project.name?.replace(FILE_EXT, '')} <span className="text-xs text-chalkboard-60">
</Link>
<span className="text-chalkboard-60 text-xs">
{numberOfFiles} file{numberOfFiles === 1 ? '' : 's'}{' '} {numberOfFiles} file{numberOfFiles === 1 ? '' : 's'}{' '}
{numberOfFolders > 0 && {numberOfFolders > 0 &&
`/ ${numberOfFolders} folder${ `/ ${numberOfFolders} folder${
numberOfFolders === 1 ? '' : 's' numberOfFolders === 1 ? '' : 's'
}`} }`}
</span> </span>
<span className="text-chalkboard-60 text-xs"> <span className="text-xs text-chalkboard-60">
Edited{' '} Edited{' '}
{project.metadata && project.metadata?.modified {project.metadata && project.metadata?.modified
? getDisplayedTime(project.metadata.modified) ? getDisplayedTime(project.metadata.modified)
: 'never'} : 'never'}
</span> </span>
<div className="absolute z-10 bottom-2 right-2 flex gap-1 items-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100"> </Link>
<ActionButton <div className="absolute z-10 flex items-center gap-1 opacity-0 bottom-2 right-2 group-hover:opacity-100 group-focus-within:opacity-100">
Element="button" <ActionButton
iconStart={{ Element="button"
icon: faPenAlt, iconStart={{
className: 'p-1', icon: faPenAlt,
iconClassName: 'dark:!text-chalkboard-20', className: 'p-1',
bgClassName: '!bg-transparent', iconClassName: 'dark:!text-chalkboard-20',
size: 'xs', bgClassName: '!bg-transparent',
}} size: 'xs',
onClick={(e) => { }}
e.stopPropagation() onClick={(e) => {
e.nativeEvent.stopPropagation() e.stopPropagation()
setIsEditing(true) e.nativeEvent.stopPropagation()
}} setIsEditing(true)
className="!p-0" }}
> className="!p-0"
<Tooltip position="left" delay={1000}> >
Rename project <Tooltip position="left" delay={1000}>
</Tooltip> Rename project
</ActionButton> </Tooltip>
<ActionButton </ActionButton>
Element="button" <ActionButton
iconStart={{ Element="button"
icon: faTrashAlt, iconStart={{
className: 'p-1', icon: faTrashAlt,
size: 'xs', className: 'p-1',
bgClassName: '!bg-transparent', size: 'xs',
iconClassName: '!text-destroy-70', bgClassName: '!bg-transparent',
}} iconClassName: '!text-destroy-70',
className="!p-0 hover:border-destroy-40 dark:hover:border-destroy-40" }}
onClick={(e) => { className="!p-0 hover:border-destroy-40 dark:hover:border-destroy-40"
e.stopPropagation() onClick={(e) => {
e.nativeEvent.stopPropagation() e.stopPropagation()
setIsConfirmingDelete(true) e.nativeEvent.stopPropagation()
}} setIsConfirmingDelete(true)
> }}
<Tooltip position="left" delay={1000}> >
Delete project <Tooltip position="left" delay={1000}>
</Tooltip> Delete project
</ActionButton> </Tooltip>
</div> </ActionButton>
</div> </div>
<Dialog <Dialog
open={isConfirmingDelete} open={isConfirmingDelete}
onClose={() => setIsConfirmingDelete(false)} onClose={() => setIsConfirmingDelete(false)}
className="relative z-50" className="relative z-50"
> >
<div className="fixed inset-0 bg-chalkboard-110/80 grid place-content-center"> <div className="fixed inset-0 grid bg-chalkboard-110/80 place-content-center">
<Dialog.Panel className="rounded p-4 bg-chalkboard-10 dark:bg-chalkboard-100 border border-destroy-80 max-w-2xl"> <Dialog.Panel className="max-w-2xl p-4 border rounded bg-chalkboard-10 dark:bg-chalkboard-100 border-destroy-80">
<Dialog.Title as="h2" className="text-2xl font-bold mb-4"> <Dialog.Title as="h2" className="mb-4 text-2xl font-bold">
Delete File Delete File
</Dialog.Title> </Dialog.Title>
<Dialog.Description> <Dialog.Description>

View File

@ -24,6 +24,7 @@ const projectWellFormed = {
}, },
kcl_file_count: 1, kcl_file_count: 1,
directory_count: 0, directory_count: 0,
default_file: '/some/path/Simple Box/main.kcl',
} satisfies Project } satisfies Project
describe('ProjectSidebarMenu tests', () => { describe('ProjectSidebarMenu tests', () => {
@ -32,7 +33,7 @@ describe('ProjectSidebarMenu tests', () => {
<BrowserRouter> <BrowserRouter>
<CommandBarProvider> <CommandBarProvider>
<SettingsAuthProviderJest> <SettingsAuthProviderJest>
<ProjectSidebarMenu project={projectWellFormed} /> <ProjectSidebarMenu project={projectWellFormed} enableMenu={true} />
</SettingsAuthProviderJest> </SettingsAuthProviderJest>
</CommandBarProvider> </CommandBarProvider>
</BrowserRouter> </BrowserRouter>
@ -53,7 +54,7 @@ describe('ProjectSidebarMenu tests', () => {
<BrowserRouter> <BrowserRouter>
<CommandBarProvider> <CommandBarProvider>
<SettingsAuthProviderJest> <SettingsAuthProviderJest>
<ProjectSidebarMenu /> <ProjectSidebarMenu enableMenu={true} />
</SettingsAuthProviderJest> </SettingsAuthProviderJest>
</CommandBarProvider> </CommandBarProvider>
</BrowserRouter> </BrowserRouter>
@ -64,22 +65,18 @@ describe('ProjectSidebarMenu tests', () => {
expect(screen.getByTestId('projectName')).toHaveTextContent(APP_NAME) expect(screen.getByTestId('projectName')).toHaveTextContent(APP_NAME)
}) })
test('Renders as a link if set to do so', () => { test('Disables popover menu by default', () => {
render( render(
<BrowserRouter> <BrowserRouter>
<CommandBarProvider> <CommandBarProvider>
<SettingsAuthProviderJest> <SettingsAuthProviderJest>
<ProjectSidebarMenu <ProjectSidebarMenu project={projectWellFormed} />
project={projectWellFormed}
renderAsLink={true}
/>
</SettingsAuthProviderJest> </SettingsAuthProviderJest>
</CommandBarProvider> </CommandBarProvider>
</BrowserRouter> </BrowserRouter>
) )
expect(screen.getByTestId('project-sidebar-link')).toBeInTheDocument() expect(screen.getByTestId('project-name')).toHaveTextContent(
expect(screen.getByTestId('project-sidebar-link-name')).toHaveTextContent(
projectWellFormed.name projectWellFormed.name
) )
}) })

View File

@ -17,53 +17,63 @@ import { engineCommandManager } from 'lib/singletons'
const ProjectSidebarMenu = ({ const ProjectSidebarMenu = ({
project, project,
file, file,
renderAsLink = false, enableMenu = false,
}: { }: {
renderAsLink?: boolean enableMenu?: boolean
project?: IndexLoaderData['project'] project?: IndexLoaderData['project']
file?: IndexLoaderData['file'] file?: IndexLoaderData['file']
}) => { }) => {
const { onProjectClose } = useLspContext()
return ( return (
<div className="!no-underline h-full mr-auto max-h-min min-h-12 min-w-max flex items-center gap-2"> <div className="!no-underline h-full mr-auto max-h-min min-h-12 min-w-max flex items-center gap-2">
<Link <AppLogoLink project={project} file={file} />
onClick={() => { {enableMenu ? (
onProjectClose(file || null, project?.path || null, false)
// Clear the scene and end the session.
engineCommandManager.endSession()
}}
to={paths.HOME}
className="relative h-full grid place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-2.5 before:z-[-1] before:bg-primary hover:before:brightness-110 before:rounded-b-sm"
>
<Logo className="w-auto h-4 text-chalkboard-10" />
</Link>
{renderAsLink ? (
<>
<Link
onClick={() => {
onProjectClose(file || null, project?.path || null, false)
// Clear the scene and end the session.
engineCommandManager.endSession()
}}
to={paths.HOME}
className="!no-underline"
data-testid="project-sidebar-link"
>
<span
className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
data-testid="project-sidebar-link-name"
>
{project?.name ? project.name : APP_NAME}
</span>
</Link>
</>
) : (
<ProjectMenuPopover project={project} file={file} /> <ProjectMenuPopover project={project} file={file} />
) : (
<span
className="hidden select-none cursor-default text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
data-testid="project-name"
>
{project?.name ? project.name : APP_NAME}
</span>
)} )}
</div> </div>
) )
} }
function AppLogoLink({
project,
file,
}: {
project?: IndexLoaderData['project']
file?: IndexLoaderData['file']
}) {
const { onProjectClose } = useLspContext()
const wrapperClassName =
"relative h-full grid place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-2.5 before:z-[-1] before:bg-primary before:rounded-b-sm"
const logoClassName = 'w-auto h-4 text-chalkboard-10'
return isTauri() ? (
<Link
data-testid="app-logo"
onClick={() => {
onProjectClose(file || null, project?.path || null, false)
// Clear the scene and end the session.
engineCommandManager.endSession()
}}
to={paths.HOME}
className={wrapperClassName + ' hover:before:brightness-110'}
>
<Logo className={logoClassName} />
<span className="sr-only">{APP_NAME}</span>
</Link>
) : (
<div className={wrapperClassName} data-testid="app-logo">
<Logo className={logoClassName} />
<span className="sr-only">{APP_NAME}</span>
</div>
)
}
function ProjectMenuPopover({ function ProjectMenuPopover({
project, project,
file, file,

View File

@ -172,7 +172,7 @@ export const SettingsAuthProviderBase = ({
}, },
'Execute AST': () => kclManager.executeCode(true), 'Execute AST': () => kclManager.executeCode(true),
persistSettings: (context) => persistSettings: (context) =>
saveSettings(context, loadedProject?.project?.name), saveSettings(context, loadedProject?.project?.path),
}, },
} }
) )

View File

@ -134,6 +134,7 @@ code {
#code-mirror-override > div, #code-mirror-override > div,
#code-mirror-override .cm-editor { #code-mirror-override .cm-editor {
@apply bg-transparent h-full; @apply bg-transparent h-full;
@apply select-auto;
} }
#code-mirror-override .cm-scroller { #code-mirror-override .cm-scroller {

View File

@ -188,7 +188,7 @@ export class KclManager {
engineCommandManager: this.engineCommandManager, engineCommandManager: this.engineCommandManager,
}) })
sceneInfra.modelingSend({ type: 'code edit during sketch' }) sceneInfra.modelingSend({ type: 'code edit during sketch' })
enterEditMode(programMemory, this.engineCommandManager) defaultSelectionFilter(programMemory, this.engineCommandManager)
this.isExecuting = false this.isExecuting = false
// Check the cancellation token for this execution before applying side effects // Check the cancellation token for this execution before applying side effects
if (this._cancelTokens.get(currentExecutionId)) { if (this._cancelTokens.get(currentExecutionId)) {
@ -348,9 +348,6 @@ export class KclManager {
void this.engineCommandManager.setPlaneHidden(this.defaultPlanes.yz, true) void this.engineCommandManager.setPlaneHidden(this.defaultPlanes.yz, true)
void this.engineCommandManager.setPlaneHidden(this.defaultPlanes.xz, true) void this.engineCommandManager.setPlaneHidden(this.defaultPlanes.xz, true)
} }
enterEditMode() {
enterEditMode(this.programMemory, this.engineCommandManager)
}
exitEditMode() { exitEditMode() {
this.engineCommandManager.sendSceneCommand({ this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
@ -358,9 +355,12 @@ export class KclManager {
cmd: { type: 'edit_mode_exit' }, cmd: { type: 'edit_mode_exit' },
}) })
} }
defaultSelectionFilter() {
defaultSelectionFilter(this.programMemory, this.engineCommandManager)
}
} }
function enterEditMode( function defaultSelectionFilter(
programMemory: ProgramMemory, programMemory: ProgramMemory,
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
) { ) {

View File

@ -6,6 +6,7 @@ import { isTauri } from 'lib/isTauri'
import { writeTextFile } from '@tauri-apps/plugin-fs' import { writeTextFile } from '@tauri-apps/plugin-fs'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { editorManager } from 'lib/singletons' import { editorManager } from 'lib/singletons'
import { KeyBinding } from '@uiw/react-codemirror'
const PERSIST_CODE_TOKEN = 'persistCode' const PERSIST_CODE_TOKEN = 'persistCode'
@ -13,6 +14,7 @@ export default class CodeManager {
private _code: string = bracket private _code: string = bracket
#updateState: (arg: string) => void = () => {} #updateState: (arg: string) => void = () => {}
private _currentFilePath: string | null = null private _currentFilePath: string | null = null
private _hotkeys: { [key: string]: () => void } = {}
constructor() { constructor() {
if (isTauri()) { if (isTauri()) {
@ -48,6 +50,20 @@ export default class CodeManager {
this.#updateState = setCode this.#updateState = setCode
} }
registerHotkey(hotkey: string, callback: () => void) {
this._hotkeys[hotkey] = callback
}
getCodemirrorHotkeys(): KeyBinding[] {
return Object.keys(this._hotkeys).map((key) => ({
key,
run: () => {
this._hotkeys[key]()
return false
},
}))
}
updateCurrentFilePath(path: string) { updateCurrentFilePath(path: string) {
this._currentFilePath = path this._currentFilePath = path
} }

View File

@ -1,20 +1,21 @@
import { ToolTip } from '../useStore' import { ToolTip } from '../useStore'
import { Selection, Selections } from 'lib/selections' import { Selection, Selections } from 'lib/selections'
import { import {
ArrayExpression,
BinaryExpression, BinaryExpression,
Program,
SyntaxType,
Value,
CallExpression, CallExpression,
ExpressionStatement, ExpressionStatement,
VariableDeclaration,
ReturnStatement,
ArrayExpression,
PathToNode, PathToNode,
PipeExpression,
Program,
ProgramMemory, ProgramMemory,
ReturnStatement,
SketchGroup, SketchGroup,
SourceRange, SourceRange,
PipeExpression, SyntaxType,
Value,
VariableDeclaration,
VariableDeclarator,
} from './wasm' } from './wasm'
import { createIdentifier, splitPathAtLastIndex } from './modifyAst' import { createIdentifier, splitPathAtLastIndex } from './modifyAst'
import { getSketchSegmentFromSourceRange } from './std/sketchConstraints' import { getSketchSegmentFromSourceRange } from './std/sketchConstraints'
@ -295,6 +296,58 @@ export function getNodePathFromSourceRange(
return path return path
} }
type KCLNode =
| Value
| ExpressionStatement
| VariableDeclaration
| VariableDeclarator
| ReturnStatement
export function traverse(
node: KCLNode,
option: {
enter?: (node: KCLNode) => void
leave?: (node: KCLNode) => void
}
) {
option?.enter?.(node)
const _traverse = (node: KCLNode) => traverse(node, option)
if (node.type === 'VariableDeclaration') {
node.declarations.forEach(_traverse)
} else if (node.type === 'VariableDeclarator') {
_traverse(node.init)
} else if (node.type === 'PipeExpression') {
node.body.forEach(_traverse)
} else if (node.type === 'CallExpression') {
_traverse(node.callee)
node.arguments.forEach(_traverse)
} else if (node.type === 'BinaryExpression') {
_traverse(node.left)
_traverse(node.right)
} else if (node.type === 'Identifier') {
// do nothing
} else if (node.type === 'Literal') {
// do nothing
} else if (node.type === 'ArrayExpression') {
node.elements.forEach(_traverse)
} else if (node.type === 'ObjectExpression') {
node.properties.forEach(({ key, value }) => {
_traverse(key)
_traverse(value)
})
} else if (node.type === 'UnaryExpression') {
_traverse(node.argument)
} else if (node.type === 'MemberExpression') {
// hmm this smell
_traverse(node.object)
_traverse(node.property)
} else if ('body' in node && Array.isArray(node.body)) {
node.body.forEach(_traverse)
}
option?.leave?.(node)
}
export interface PrevVariable<T> { export interface PrevVariable<T> {
key: string key: string
value: T value: T

View File

@ -54,8 +54,16 @@ interface PendingCommand extends CommandInfo {
resolve: (val: ResolveCommand) => void resolve: (val: ResolveCommand) => void
} }
/**
* The ArtifactMap is a client-side representation of the artifacts that
* have been sent to the server-side engine. It is used to keep track of
* the state of each command, and to resolve the promise that was returned.
* It is also used to keep track of what entities are in the engine scene,
* so that we can associate IDs returned from the engine with the
* lines of KCL code that generated them.
*/
export interface ArtifactMap { export interface ArtifactMap {
[key: string]: ResultCommand | PendingCommand | FailedCommand [commandId: string]: ResultCommand | PendingCommand | FailedCommand
} }
interface NewTrackArgs { interface NewTrackArgs {
@ -63,10 +71,11 @@ interface NewTrackArgs {
mediaStream: MediaStream mediaStream: MediaStream
} }
// This looks funny, I know. This is needed because node and the browser /** This looks funny, I know. This is needed because node and the browser
// disagree as to the type. In a browser it's a number, but in node it's a * disagree as to the type. In a browser it's a number, but in node it's a
// "Timeout". * "Timeout".
type Timeout = ReturnType<typeof setTimeout> */
type IsomorphicTimeout = ReturnType<typeof setTimeout>
type ClientMetrics = Models['ClientMetrics_type'] type ClientMetrics = Models['ClientMetrics_type']
@ -188,9 +197,11 @@ export type EngineConnectionState =
| State<EngineConnectionStateType.Disconnecting, DisconnectingValue> | State<EngineConnectionStateType.Disconnecting, DisconnectingValue>
| State<EngineConnectionStateType.Disconnected, void> | State<EngineConnectionStateType.Disconnected, void>
// EngineConnection encapsulates the connection(s) to the Engine /**
// for the EngineCommandManager; namely, the underlying WebSocket * EngineConnection encapsulates the connection(s) to the Engine
// and WebRTC connections. * for the EngineCommandManager; namely, the underlying WebSocket
* and WebRTC connections.
*/
class EngineConnection { class EngineConnection {
websocket?: WebSocket websocket?: WebSocket
pc?: RTCPeerConnection pc?: RTCPeerConnection
@ -227,23 +238,40 @@ class EngineConnection {
this.onConnectionStateChange(this._state) this.onConnectionStateChange(this._state)
} }
private failedConnTimeout: Timeout | null private failedConnTimeout: IsomorphicTimeout | null
readonly url: string readonly url: string
private readonly token?: string private readonly token?: string
// For now, this is only used by the NetworkHealthIndicator. /**For now, this is only used by the NetworkHealthIndicator.
// We can eventually use it for more, but one step at a time. * We can eventually use it for more, but one step at a time.
*/
private onConnectionStateChange: (state: EngineConnectionState) => void private onConnectionStateChange: (state: EngineConnectionState) => void
// These are used for the EngineCommandManager and were created /**
// before onConnectionStateChange existed. * Used for the EngineCommandManager, created before
* onConnectionStateChange existed.
*/
private onEngineConnectionOpen: (engineConnection: EngineConnection) => void private onEngineConnectionOpen: (engineConnection: EngineConnection) => void
/**
* Used for the EngineCommandManager, created before
* onConnectionStateChange existed.
*/
private onConnectionStarted: (engineConnection: EngineConnection) => void private onConnectionStarted: (engineConnection: EngineConnection) => void
/**
* Used for the EngineCommandManager, created before
* onConnectionStateChange existed.
*/
private onClose: (engineConnection: EngineConnection) => void private onClose: (engineConnection: EngineConnection) => void
/**
* Used for the EngineCommandManager, created before
* onConnectionStateChange existed.
*/
private onNewTrack: (track: NewTrackArgs) => void private onNewTrack: (track: NewTrackArgs) => void
// TODO: actual type is ClientMetrics /**
* @todo actual type is `ClientMetrics`
*/
public webrtcStatsCollector?: () => Promise<WebRTCClientMetrics> public webrtcStatsCollector?: () => Promise<WebRTCClientMetrics>
private engineCommandManager: EngineCommandManager private engineCommandManager: EngineCommandManager
@ -322,11 +350,13 @@ class EngineConnection {
} }
} }
// connect will attempt to connect to the Engine over a WebSocket, and /**
// establish the WebRTC connections. * Attempts to connect to the Engine over a WebSocket, and
// * establish the WebRTC connections.
// This will attempt the full handshake, and retry if the connection *
// did not establish. * This will attempt the full handshake, and retry if the connection
* did not establish.
*/
connect() { connect() {
if (this.isConnecting() || this.isReady()) { if (this.isConnecting() || this.isReady()) {
return return
@ -521,6 +551,7 @@ class EngineConnection {
// Everything is now connected. // Everything is now connected.
this.state = { type: EngineConnectionStateType.ConnectionEstablished } this.state = { type: EngineConnectionStateType.ConnectionEstablished }
this.engineCommandManager.inSequence = 1
this.onEngineConnectionOpen(this) this.onEngineConnectionOpen(this)
}) })
@ -908,21 +939,66 @@ export type CommandLog =
data: null data: null
} }
/**
* The EngineCommandManager is the main interface to the Engine for Modeling App.
*
* It is responsible for sending commands to the Engine, and managing the state
* of those commands. It also sets up and tears down the connection to the Engine
* through the {@link EngineConnection} class.
*
* It also maintains an {@link artifactMap} that keeps track of the state of each
* command, and the artifacts that have been generated by those commands.
*/
export class EngineCommandManager { export class EngineCommandManager {
/**
* The artifactMap is a client-side representation of the commands that have been sent
* to the server-side geometry engine, and the state of their resulting artifacts.
*
* It is used to keep track of the state of each command, which can fail, succeed, or be
* pending.
*
* It is also used to keep track of our client's understanding of what is in the engine scene
* so that we can map to and from KCL code. Each artifact maintains a source range to the part
* of the KCL code that generated it.
*/
artifactMap: ArtifactMap = {} artifactMap: ArtifactMap = {}
/**
* The {@link ArtifactMap} from the previous engine connection. This is used as a fallback
* when the engine connection is reset without a full client-side refresh.
*
* @deprecated This was used during a short time when we were choosing to not execute the engine in certain cases.
*/
lastArtifactMap: ArtifactMap = {} lastArtifactMap: ArtifactMap = {}
/**
* The client-side representation of the scene command artifacts that have been sent to the server;
* that is, the *non-modeling* commands and corresponding artifacts.
*
* For modeling commands, see {@link artifactMap}.
*/
sceneCommandArtifacts: ArtifactMap = {} sceneCommandArtifacts: ArtifactMap = {}
/**
* A counter that is incremented with each command sent over the *unreliable* channel to the engine.
* This is compared to the latest received {@link inSequence} number to determine if we should ignore
* any out-of-order late responses in the unreliable channel.
*/
outSequence = 1 outSequence = 1
/**
* The latest sequence number received from the engine over the *unreliable* channel.
* This is compared to the {@link outSequence} number to determine if we should ignore
* any out-of-order late responses in the unreliable channel.
*/
inSequence = 1 inSequence = 1
pool?: string pool?: string
engineConnection?: EngineConnection engineConnection?: EngineConnection
defaultPlanes: DefaultPlanes | null = null defaultPlanes: DefaultPlanes | null = null
commandLogs: CommandLog[] = [] commandLogs: CommandLog[] = []
_commandLogCallBack: (command: CommandLog[]) => void = () => {} _commandLogCallBack: (command: CommandLog[]) => void = () => {}
// Folks should realize that wait for ready does not get called _everytime_
// the connection resets and restarts, it only gets called the first time.
// Be careful what you put here.
private resolveReady = () => {} private resolveReady = () => {}
/** Folks should realize that wait for ready does not get called _everytime_
* the connection resets and restarts, it only gets called the first time.
*
* Be careful what you put here.
*/
waitForReady: Promise<void> = new Promise((resolve) => { waitForReady: Promise<void> = new Promise((resolve) => {
this.resolveReady = resolve this.resolveReady = resolve
}) })

View File

@ -1,5 +1,6 @@
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { CommandSetConfig, KclCommandValue } from 'lib/commandTypes' import { CommandSetConfig, KclCommandValue } from 'lib/commandTypes'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import { Selections } from 'lib/selections' import { Selections } from 'lib/selections'
import { modelingMachine } from 'machines/modelingMachine' import { modelingMachine } from 'machines/modelingMachine'
@ -135,7 +136,7 @@ export const modelingMachineConfig: CommandSetConfig<
// }, // },
distance: { distance: {
inputType: 'kcl', inputType: 'kcl',
defaultValue: '5 + 7', defaultValue: KCL_DEFAULT_LENGTH,
required: true, required: true,
}, },
}, },

View File

@ -42,3 +42,5 @@ export const RELEVANT_FILE_TYPES = [
] as const ] as const
/** The default name for a tutorial project */ /** The default name for a tutorial project */
export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn' export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn'
/** The default KCL length expression */
export const KCL_DEFAULT_LENGTH = `5`

37
src/lib/hotkeyWrapper.ts Normal file
View File

@ -0,0 +1,37 @@
import { Options, useHotkeys } from 'react-hotkeys-hook'
import { useEffect } from 'react'
import { codeManager } from './singletons'
// Hotkey wrapper wraps hotkeys for the app (outside of the editor)
// With hotkeys inside the editor.
// This way we can have hotkeys defined in one place and not have to worry about
// conflicting hotkeys, or them only being implemented for the app but not
// inside the editor.
// TODO: would be nice if this didn't have to be a react hook. It's not needed
// for the code mirror stuff but but it is needed for the useHotkeys hook.
export default function useHotkeyWrapper(
hotkey: string[],
callback: () => void,
additionalOptions?: Options
) {
useHotkeys(hotkey, callback, additionalOptions)
useEffect(() => {
for (const key of hotkey) {
const keybinding = mapHotkeyToCodeMirrorHotkey(key)
codeManager.registerHotkey(keybinding, callback)
}
})
}
// Convert hotkey to code mirror hotkey
// See: https://codemirror.net/docs/ref/#view.KeyBinding
function mapHotkeyToCodeMirrorHotkey(hotkey: string): string {
return hotkey
.replaceAll('+', '-')
.replaceAll(' ', '')
.replaceAll('mod', 'Meta')
.replaceAll('meta', 'Meta')
.replaceAll('ctrl', 'Ctrl')
.replaceAll('shift', 'Shift')
.replaceAll('alt', 'Alt')
}

View File

@ -38,8 +38,8 @@ export const settingsLoader: LoaderFunction = async ({
configuration configuration
) )
if (projectPathData) { if (projectPathData) {
const { project_name } = projectPathData const { project_path } = projectPathData
const { settings: s } = await loadAndValidateSettings(project_name) const { settings: s } = await loadAndValidateSettings(project_path)
settings = s settings = s
} }
} }
@ -118,6 +118,7 @@ export const fileLoader: LoaderFunction = async ({
children: [], children: [],
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file: project_path,
}, },
file: { file: {
name: current_file_name, name: current_file_name,

View File

@ -77,7 +77,29 @@ export async function getEventForSelectWithPoint(
}, },
} }
} }
const _artifact = engineCommandManager.artifactMap[data.entity_id] let _artifact = engineCommandManager.artifactMap[data.entity_id]
if (!_artifact) {
// This logic for getting the parent id is for solid2ds as in edit mode it return the face id
// but we don't recognise that in the artifact map because we store the path id when the path is
// created, the solid2d is implicitly created with the close stdlib function
// there's plans to get the faceId back from the solid2d creation
// https://github.com/KittyCAD/engine/issues/2094
// at which point we can add it to the artifact map and remove this logic
const parentId = (
await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'entity_get_parent_id',
entity_id: data.entity_id,
},
cmd_id: uuidv4(),
})
)?.data?.data?.entity_id
const parentArtifact = engineCommandManager.artifactMap[parentId]
if (parentArtifact) {
_artifact = parentArtifact
}
}
const sourceRange = _artifact?.range const sourceRange = _artifact?.range
if (_artifact) { if (_artifact) {
if (_artifact.commandType === 'solid3d_get_extrusion_face_info') { if (_artifact.commandType === 'solid3d_get_extrusion_face_info') {

View File

@ -147,7 +147,7 @@ export interface AppSettings {
} }
export async function loadAndValidateSettings( export async function loadAndValidateSettings(
projectName?: string projectPath?: string
): Promise<AppSettings> { ): Promise<AppSettings> {
const settings = createSettings() const settings = createSettings()
const inTauri = isTauri() const inTauri = isTauri()
@ -166,9 +166,9 @@ export async function loadAndValidateSettings(
setSettingsAtLevel(settings, 'user', appSettingsPayload) setSettingsAtLevel(settings, 'user', appSettingsPayload)
// Load the project settings if they exist // Load the project settings if they exist
if (projectName) { if (projectPath) {
const projectSettings = inTauri const projectSettings = inTauri
? await readProjectSettingsFile(appSettings, projectName) ? await readProjectSettingsFile(projectPath)
: readLocalStorageProjectSettingsFile() : readLocalStorageProjectSettingsFile()
const projectSettingsPayload = const projectSettingsPayload =
@ -182,7 +182,7 @@ export async function loadAndValidateSettings(
export async function saveSettings( export async function saveSettings(
allSettings: typeof settings, allSettings: typeof settings,
projectName?: string projectPath?: string
) { ) {
// Make sure we have wasm initialized. // Make sure we have wasm initialized.
await initPromise await initPromise
@ -204,7 +204,7 @@ export async function saveSettings(
) )
} }
if (!projectName) { if (!projectPath) {
// If we're not saving project settings, we're done. // If we're not saving project settings, we're done.
return return
} }
@ -217,7 +217,7 @@ export async function saveSettings(
// Write the project settings. // Write the project settings.
if (inTauri) { if (inTauri) {
await writeProjectSettingsFile(appSettings, projectName, projectSettings) await writeProjectSettingsFile(projectPath, projectSettings)
} else { } else {
localStorage.setItem( localStorage.setItem(
localStorageProjectSettingsPath(), localStorageProjectSettingsPath(),

View File

@ -8,23 +8,36 @@ import { Project } from 'wasm-lib/kcl/bindings/Project'
import { FileEntry } from 'wasm-lib/kcl/bindings/FileEntry' import { FileEntry } from 'wasm-lib/kcl/bindings/FileEntry'
import { ProjectState } from 'wasm-lib/kcl/bindings/ProjectState' import { ProjectState } from 'wasm-lib/kcl/bindings/ProjectState'
import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute' import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute'
import { isTauri } from './isTauri'
// Get the app state from tauri. // Get the app state from tauri.
export async function getState(): Promise<ProjectState | undefined> { export async function getState(): Promise<ProjectState | undefined> {
if (!isTauri()) {
return undefined
}
return await invoke<ProjectState | undefined>('get_state') return await invoke<ProjectState | undefined>('get_state')
} }
// Set the app state in tauri. // Set the app state in tauri.
export async function setState(state: ProjectState | undefined): Promise<void> { export async function setState(state: ProjectState | undefined): Promise<void> {
if (!isTauri()) {
return
}
return await invoke('set_state', { state }) return await invoke('set_state', { state })
} }
// Get the initial default dir for holding all projects. // Get the initial default dir for holding all projects.
export async function getInitialDefaultDir(): Promise<string> { export async function getInitialDefaultDir(): Promise<string> {
if (!isTauri()) {
return ''
}
return invoke<string>('get_initial_default_dir') return invoke<string>('get_initial_default_dir')
} }
export async function showInFolder(path: string | undefined): Promise<void> { export async function showInFolder(path: string | undefined): Promise<void> {
if (!isTauri()) {
return
}
if (!path) { if (!path) {
console.error('path is undefined cannot call tauri showInFolder') console.error('path is undefined cannot call tauri showInFolder')
return return
@ -34,7 +47,10 @@ export async function showInFolder(path: string | undefined): Promise<void> {
export async function initializeProjectDirectory( export async function initializeProjectDirectory(
settings: Configuration settings: Configuration
): Promise<string> { ): Promise<string | undefined> {
if (!isTauri()) {
return undefined
}
return await invoke<string>('initialize_project_directory', { return await invoke<string>('initialize_project_directory', {
configuration: settings, configuration: settings,
}) })
@ -127,24 +143,20 @@ export async function writeAppSettingsFile(
// Read project settings file. // Read project settings file.
export async function readProjectSettingsFile( export async function readProjectSettingsFile(
appSettings: Configuration, projectPath: string
projectName: string
): Promise<ProjectConfiguration> { ): Promise<ProjectConfiguration> {
return await invoke<ProjectConfiguration>('read_project_settings_file', { return await invoke<ProjectConfiguration>('read_project_settings_file', {
appSettings, projectPath,
projectName,
}) })
} }
// Write project settings file. // Write project settings file.
export async function writeProjectSettingsFile( export async function writeProjectSettingsFile(
appSettings: Configuration, projectPath: string,
projectName: string,
settings: ProjectConfiguration settings: ProjectConfiguration
): Promise<void> { ): Promise<void> {
return await invoke('write_project_settings_file', { return await invoke('write_project_settings_file', {
appSettings, projectPath,
projectName,
configuration: settings, configuration: settings,
}) })
} }

View File

@ -906,12 +906,20 @@ export const modelingMachine = createMachine(
type: 'default_camera_set_perspective', type: 'default_camera_set_perspective',
}, },
}) })
const center = { x: 0, y: 0, z: 0 }
const camPos = sceneInfra.camControls.camera.position
if (camPos.x === 0 && camPos.y === 0) {
// looking straight up or down is going to cause issues with the engine
// tweaking the center to be a little off center
// TODO come up with a proper fix
center.y = 0.05
}
await engineCommandManager.sendSceneCommand({ await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_look_at', type: 'default_camera_look_at',
center: { x: 0, y: 0, z: 0 }, center,
vantage: sceneInfra.camControls.camera.position, vantage: sceneInfra.camControls.camera.position,
up: { x: 0, y: 0, z: 1 }, up: { x: 0, y: 0, z: 1 },
}, },
@ -1045,7 +1053,8 @@ export const modelingMachine = createMachine(
filter: ['face', 'plane'], filter: ['face', 'plane'],
}, },
}), }),
'set selection filter to defaults': () => kclManager.enterEditMode(), 'set selection filter to defaults': () =>
kclManager.defaultSelectionFilter(),
}, },
// end actions // end actions
} }

219
src/wasm-lib/Cargo.lock generated
View File

@ -155,9 +155,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.83" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
dependencies = [ dependencies = [
"backtrace", "backtrace",
] ]
@ -177,6 +177,15 @@ dependencies = [
"num-traits 0.2.18", "num-traits 0.2.18",
] ]
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.7.0" version = "1.7.0"
@ -246,7 +255,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -257,7 +266,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -280,7 +289,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -596,7 +605,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -846,7 +855,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -870,7 +879,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.10.0", "strsim 0.10.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -881,7 +890,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -922,7 +931,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"synstructure 0.13.1", "synstructure 0.13.1",
] ]
@ -976,7 +985,18 @@ dependencies = [
"rustfmt-wrapper", "rustfmt-wrapper",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.63", "syn 2.0.65",
]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
] ]
[[package]] [[package]]
@ -988,7 +1008,7 @@ dependencies = [
"diesel_table_macro_syntax", "diesel_table_macro_syntax",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -997,7 +1017,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
dependencies = [ dependencies = [
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1026,7 +1046,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1051,9 +1071,9 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.10.0" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
[[package]] [[package]]
name = "elliptic-curve" name = "elliptic-curve"
@ -1108,7 +1128,7 @@ checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1325,7 +1345,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1436,7 +1456,7 @@ dependencies = [
"inflections", "inflections",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -1652,7 +1672,7 @@ dependencies = [
"futures-util", "futures-util",
"http 0.2.12", "http 0.2.12",
"hyper", "hyper",
"rustls 0.21.11", "rustls 0.21.12",
"tokio", "tokio",
"tokio-rustls 0.24.1", "tokio-rustls 0.24.1",
] ]
@ -1853,18 +1873,18 @@ dependencies = [
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.11.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [ dependencies = [
"either", "either",
] ]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.12.1" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -1918,7 +1938,7 @@ dependencies = [
"iai", "iai",
"image", "image",
"insta", "insta",
"itertools 0.12.1", "itertools 0.13.0",
"js-sys", "js-sys",
"kittycad", "kittycad",
"kittycad-execution-plan-macros", "kittycad-execution-plan-macros",
@ -1959,18 +1979,18 @@ dependencies = [
"pretty_assertions", "pretty_assertions",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
name = "kittycad" name = "kittycad"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6e12eb45fd9a28c8e99dbdef54556246b39acee14e4aa6f0fc43636caa62d9" checksum = "81d3481e1b63f063ccf7d211f643da0563d2a42dd8b95b6006610742b729996b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"base64 0.21.7", "base64 0.22.1",
"bigdecimal", "bigdecimal",
"bytes", "bytes",
"chrono", "chrono",
@ -1979,10 +1999,10 @@ dependencies = [
"format_serde_error", "format_serde_error",
"futures", "futures",
"http 0.2.12", "http 0.2.12",
"itertools 0.10.5", "itertools 0.12.1",
"log", "log",
"mime_guess", "mime_guess",
"parse-display 0.8.2", "parse-display 0.9.0",
"phonenumber", "phonenumber",
"rand 0.8.5", "rand 0.8.5",
"reqwest", "reqwest",
@ -2032,7 +2052,7 @@ checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2083,7 +2103,7 @@ checksum = "385775cc9d5bf25579f3029824ca1a6e7ab1b7c338e972ec8e8fcefff801f353"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2457,7 +2477,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2614,7 +2634,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.7.5", "regex-syntax 0.7.5",
"structmeta 0.2.0", "structmeta 0.2.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2628,7 +2648,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.8.2", "regex-syntax 0.8.2",
"structmeta 0.3.0", "structmeta 0.3.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2658,14 +2678,14 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "phonenumber" name = "phonenumber"
version = "0.3.3+8.13.9" version = "0.3.5+8.13.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "635f3e6288e4f01c049d89332a031bd74f25d64b6fb94703ca966e819488cd06" checksum = "f174c8db59b620032bd52b655fc97000458850fec0db35fcd4e802b668517ec0"
dependencies = [ dependencies = [
"bincode", "bincode",
"either", "either",
"fnv", "fnv",
"itertools 0.11.0", "itertools 0.12.1",
"lazy_static", "lazy_static",
"nom", "nom",
"quick-xml", "quick-xml",
@ -2694,7 +2714,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -2841,9 +2861,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.82" version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -3078,7 +3098,7 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls 0.21.11", "rustls 0.21.12",
"rustls-pemfile 1.0.4", "rustls-pemfile 1.0.4",
"serde", "serde",
"serde_json", "serde_json",
@ -3304,9 +3324,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.21.11" version = "0.21.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [ dependencies = [
"log", "log",
"ring 0.17.8", "ring 0.17.8",
@ -3316,9 +3336,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.22.2" version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
dependencies = [ dependencies = [
"log", "log",
"ring 0.17.8", "ring 0.17.8",
@ -3419,9 +3439,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.17" version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309" checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"bytes", "bytes",
@ -3436,14 +3456,14 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.17" version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108" checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde_derive_internals", "serde_derive_internals",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3519,9 +3539,9 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.201" version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -3537,13 +3557,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.201" version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3554,7 +3574,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3577,14 +3597,14 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "0.6.5" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -3598,7 +3618,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3773,7 +3793,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive 0.2.0", "structmeta-derive 0.2.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3785,7 +3805,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive 0.3.0", "structmeta-derive 0.3.0",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3796,7 +3816,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3807,7 +3827,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -3879,9 +3899,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.63" version = "2.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3914,7 +3934,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4000,22 +4020,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.60" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.60" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4122,7 +4142,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4141,7 +4161,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [ dependencies = [
"rustls 0.21.11", "rustls 0.21.12",
"tokio", "tokio",
] ]
@ -4151,7 +4171,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
dependencies = [ dependencies = [
"rustls 0.22.2", "rustls 0.22.4",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
] ]
@ -4164,7 +4184,7 @@ checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
"rustls 0.22.2", "rustls 0.22.4",
"rustls-native-certs", "rustls-native-certs",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
@ -4188,9 +4208,9 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.8.12" version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned", "serde_spanned",
@ -4200,18 +4220,18 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.5" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.22.9" version = "0.22.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c"
dependencies = [ dependencies = [
"indexmap 2.2.5", "indexmap 2.2.5",
"serde", "serde",
@ -4285,7 +4305,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4313,7 +4333,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4390,7 +4410,7 @@ dependencies = [
"Inflector", "Inflector",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"termcolor", "termcolor",
] ]
@ -4407,7 +4427,7 @@ dependencies = [
"httparse", "httparse",
"log", "log",
"rand 0.8.5", "rand 0.8.5",
"rustls 0.22.2", "rustls 0.22.4",
"rustls-pki-types", "rustls-pki-types",
"sha1", "sha1",
"thiserror", "thiserror",
@ -4586,7 +4606,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -4662,7 +4682,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -4697,7 +4717,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -4800,7 +4820,7 @@ dependencies = [
"ring 0.17.8", "ring 0.17.8",
"rtcp", "rtcp",
"rtp", "rtp",
"rustls 0.21.11", "rustls 0.21.12",
"sdp", "sdp",
"serde", "serde",
"serde_json", "serde_json",
@ -4860,7 +4880,7 @@ dependencies = [
"rand_core 0.6.4", "rand_core 0.6.4",
"rcgen", "rcgen",
"ring 0.17.8", "ring 0.17.8",
"rustls 0.21.11", "rustls 0.21.12",
"sec1", "sec1",
"serde", "serde",
"sha1", "sha1",
@ -5269,7 +5289,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
@ -5289,18 +5309,21 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.63", "syn 2.0.65",
] ]
[[package]] [[package]]
name = "zip" name = "zip"
version = "0.6.6" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" checksum = "f1f4a27345eb6f7aa7bd015ba7eb4175fa4e1b462a29874b779e0bbcf96c6ac7"
dependencies = [ dependencies = [
"byteorder", "arbitrary",
"crc32fast", "crc32fast",
"crossbeam-utils", "crossbeam-utils",
"displaydoc",
"indexmap 2.2.5",
"thiserror",
] ]
[[package]] [[package]]

View File

@ -17,7 +17,7 @@ kcl-lib = { path = "kcl" }
kittycad = { workspace = true } kittycad = { workspace = true }
serde_json = "1.0.116" serde_json = "1.0.116"
tokio = { version = "1.37.0", features = ["sync"] } tokio = { version = "1.37.0", features = ["sync"] }
toml = "0.8.12" toml = "0.8.13"
uuid = { version = "1.8.0", features = ["v4", "js", "serde"] } uuid = { version = "1.8.0", features = ["v4", "js", "serde"] }
wasm-bindgen = "0.2.91" wasm-bindgen = "0.2.91"
wasm-bindgen-futures = "0.4.42" wasm-bindgen-futures = "0.4.42"

View File

@ -18,12 +18,12 @@ once_cell = "1.19.0"
proc-macro2 = "1" proc-macro2 = "1"
quote = "1" quote = "1"
regex = "1.10" regex = "1.10"
serde = { version = "1.0.201", features = ["derive"] } serde = { version = "1.0.202", features = ["derive"] }
serde_tokenstream = "0.2" serde_tokenstream = "0.2"
syn = { version = "2.0.63", features = ["full"] } syn = { version = "2.0.65", features = ["full"] }
[dev-dependencies] [dev-dependencies]
anyhow = "1.0.83" anyhow = "1.0.86"
expectorate = "1.1.0" expectorate = "1.1.0"
pretty_assertions = "1.4.0" pretty_assertions = "1.4.0"
rustfmt-wrapper = "0.2.1" rustfmt-wrapper = "0.2.1"

View File

@ -201,7 +201,7 @@ fn do_stdlib_inner(
.code_blocks .code_blocks
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, code_block)| generate_code_block_test(&fn_name_str, code_block, index, &metadata.tags)) .map(|(index, code_block)| generate_code_block_test(&fn_name_str, code_block, index))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let tags = metadata let tags = metadata
@ -731,27 +731,13 @@ fn parse_array_type(type_name: &str) -> Option<(&str, usize)> {
// For each kcl code block, we want to generate a test that checks that the // For each kcl code block, we want to generate a test that checks that the
// code block is valid kcl code and compiles and executes. // code block is valid kcl code and compiles and executes.
fn generate_code_block_test( fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> proc_macro2::TokenStream {
fn_name: &str,
code_block: &str,
index: usize,
tags: &[String],
) -> proc_macro2::TokenStream {
let test_name = format_ident!("serial_test_example_{}{}", fn_name, index); let test_name = format_ident!("serial_test_example_{}{}", fn_name, index);
let test_name_mock = format_ident!("test_mock_example_{}{}", fn_name, index); let test_name_mock = format_ident!("test_mock_example_{}{}", fn_name, index);
let test_name_str = format!("serial_test_example_{}{}", fn_name, index); let test_name_str = format!("serial_test_example_{}{}", fn_name, index);
// TODO: We ignore import for now, because the files don't exist and we just want
// to show easy imports.
let ignored = if tags.contains(&"norun".to_string()) {
quote! { #[ignore] }
} else {
quote! {}
};
quote! { quote! {
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
#ignored
async fn #test_name_mock() { async fn #test_name_mock() {
let tokens = crate::token::lexer(#code_block).unwrap(); let tokens = crate::token::lexer(#code_block).unwrap();
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
@ -768,7 +754,6 @@ fn generate_code_block_test(
} }
#[tokio::test(flavor = "multi_thread", worker_threads = 5)] #[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#ignored
async fn #test_name() { async fn #test_name() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),); let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder() let http_client = reqwest::Client::builder()

View File

@ -340,43 +340,6 @@ fn test_stdlib_doc_comment_with_code() {
expectorate::assert_contents("tests/doc_comment_with_code.gen", &get_text_fmt(&item).unwrap()); expectorate::assert_contents("tests/doc_comment_with_code.gen", &get_text_fmt(&item).unwrap());
} }
#[test]
fn test_stdlib_doc_comment_with_code_on_ignored_function() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
tags = ["norun"]
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// import
///
/// ```
/// This is another code block.
/// yes sirrr.
/// import
/// ```
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/doc_comment_with_code_on_ignored_function.gen",
&get_text_fmt(&item).unwrap(),
);
}
#[test] #[test]
fn test_stdlib_fail_non_camel_case() { fn test_stdlib_fail_non_camel_case() {
let (_, errors) = do_stdlib( let (_, errors) = do_stdlib(

View File

@ -1,303 +0,0 @@
#[cfg(test)]
mod test_examples_import {
#[tokio::test(flavor = "multi_thread")]
#[ignore]
async fn test_mock_example_import0() {
let tokens =
crate::token::lexer("This is another code block.\nyes sirrr.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new()
.await
.unwrap(),
)),
fs: std::sync::Arc::new(crate::fs::FileManager::new()),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
is_mock: true,
};
ctx.run(program, None).await.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens =
crate::token::lexer("This is another code block.\nyes sirrr.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(program, None).await.unwrap();
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
&actual,
1.0,
);
}
#[tokio::test(flavor = "multi_thread")]
#[ignore]
async fn test_mock_example_import1() {
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new()
.await
.unwrap(),
)),
fs: std::sync::Arc::new(crate::fs::FileManager::new()),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
is_mock: true,
};
ctx.run(program, None).await.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import1() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(program, None).await.unwrap();
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_import1"),
&actual,
1.0,
);
}
}
#[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)]
pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
pub(crate) const Import: Import = Import {};
fn boxed_import(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
> + Send,
>,
> {
Box::pin(import(args))
}
impl crate::docs::StdLibFn for Import {
fn name(&self) -> String {
"import".to_string()
}
fn summary(&self) -> String {
"This is some function.".to_string()
}
fn description(&self) -> String {
"It does shit.".to_string()
}
fn tags(&self) -> Vec<String> {
vec!["norun".to_string()]
}
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: <Option<kittycad::types::InputFormat>>::json_schema(&mut generator),
required: false,
}]
}
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[SketchGroup]".to_string(),
schema: <Vec<SketchGroup>>::json_schema(&mut generator),
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nimport",
"This is code.\nIt does other shit.\nimport",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb).unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
Box::new(self.clone())
}
}
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" import"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" import"]
#[doc = r" ```"]
fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<Box<SketchGroup>>> {
args
}

View File

@ -14,7 +14,7 @@ kittycad-execution-plan-traits = { workspace = true }
kittycad-execution-plan-macros = { workspace = true } kittycad-execution-plan-macros = { workspace = true }
kittycad-modeling-cmds = { workspace = true } kittycad-modeling-cmds = { workspace = true }
kittycad-modeling-session = { workspace = true } kittycad-modeling-session = { workspace = true }
thiserror = "1.0.60" thiserror = "1.0.61"
tokio = { version = "1.37.0", features = ["macros", "rt"] } tokio = { version = "1.37.0", features = ["macros", "rt"] }
twenty-twenty = "0.7.0" twenty-twenty = "0.7.0"
uuid = "1.8" uuid = "1.8"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -15,7 +15,7 @@ databake = "0.1.7"
kcl-lib = { path = "../kcl" } kcl-lib = { path = "../kcl" }
proc-macro2 = "1" proc-macro2 = "1"
quote = "1" quote = "1"
syn = { version = "2.0.63", features = ["full"] } syn = { version = "2.0.65", features = ["full"] }
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.0" pretty_assertions = "1.4.0"

View File

@ -11,7 +11,7 @@ keywords = ["kcl", "KittyCAD", "CAD"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = { version = "1.0.83", features = ["backtrace"] } anyhow = { version = "1.0.86", features = ["backtrace"] }
async-recursion = "1.1.1" async-recursion = "1.1.1"
async-trait = "0.1.80" async-trait = "0.1.80"
base64 = "0.22.1" base64 = "0.22.1"
@ -33,17 +33,17 @@ parse-display = "0.9.0"
reqwest = { version = "0.11.26", default-features = false, features = ["stream", "rustls-tls"] } reqwest = { version = "0.11.26", default-features = false, features = ["stream", "rustls-tls"] }
ropey = "1.6.1" ropey = "1.6.1"
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] } schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] }
serde = { version = "1.0.201", features = ["derive"] } serde = { version = "1.0.202", features = ["derive"] }
serde_json = "1.0.116" serde_json = "1.0.116"
sha2 = "0.10.8" sha2 = "0.10.8"
thiserror = "1.0.60" thiserror = "1.0.61"
toml = "0.8.12" toml = "0.8.13"
ts-rs = { version = "7.1.1", features = ["uuid-impl", "url-impl", "chrono-impl"] } ts-rs = { version = "7.1.1", features = ["uuid-impl", "url-impl", "chrono-impl", "no-serde-warnings"] }
url = { version = "2.5.0", features = ["serde"] } url = { version = "2.5.0", features = ["serde"] }
uuid = { version = "1.8.0", features = ["v4", "js", "serde"] } uuid = { version = "1.8.0", features = ["v4", "js", "serde"] }
validator = { version = "0.18.1", features = ["derive"] } validator = { version = "0.18.1", features = ["derive"] }
winnow = "0.5.40" winnow = "0.5.40"
zip = { version = "0.6.6", default-features = false } zip = { version = "1.3.0", default-features = false }
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = { version = "0.3.69" } js-sys = { version = "0.3.69" }
@ -80,7 +80,7 @@ expectorate = "1.1.0"
iai = "0.1" iai = "0.1"
image = "0.24.9" image = "0.24.9"
insta = { version = "1.38.0", features = ["json"] } insta = { version = "1.38.0", features = ["json"] }
itertools = "0.12.1" itertools = "0.13.0"
pretty_assertions = "1.4.0" pretty_assertions = "1.4.0"
tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros", "time"] } tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros", "time"] }
twenty-twenty = "0.7.0" twenty-twenty = "0.7.0"

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

@ -64,10 +64,59 @@ dependencies = [
] ]
[[package]] [[package]]
name = "anyhow" name = "anstream"
version = "1.0.81" version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]]
name = "anstyle-parse"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]]
name = "anyhow"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
dependencies = [ dependencies = [
"backtrace", "backtrace",
] ]
@ -105,24 +154,24 @@ dependencies = [
[[package]] [[package]]
name = "async-recursion" name = "async-recursion"
version = "1.1.0" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.79" version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -176,6 +225,12 @@ version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bigdecimal" name = "bigdecimal"
version = "0.4.1" version = "0.4.1"
@ -287,9 +342,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.37" version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",
@ -300,6 +355,54 @@ dependencies = [
"windows-targets 0.52.0", "windows-targets 0.52.0",
] ]
[[package]]
name = "clap"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"unicase",
"unicode-width",
]
[[package]]
name = "clap_derive"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.64",
]
[[package]]
name = "clap_lex"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "colorchoice"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]] [[package]]
name = "colored" name = "colored"
version = "2.1.0" version = "2.1.0"
@ -369,6 +472,41 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "darling"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.64",
]
[[package]]
name = "darling_macro"
version = "0.20.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
dependencies = [
"darling_core",
"quote",
"syn 2.0.64",
]
[[package]] [[package]]
name = "dashmap" name = "dashmap"
version = "5.5.3" version = "5.5.3"
@ -407,7 +545,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
"synstructure", "synstructure",
] ]
@ -419,9 +557,7 @@ checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
[[package]] [[package]]
name = "derive-docs" name = "derive-docs"
version = "0.1.12" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138b94245509a9dd516008788b585c34847829cf37b40a758b4aa581cf94f147"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"convert_case", "convert_case",
@ -431,7 +567,7 @@ dependencies = [
"regex", "regex",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -479,9 +615,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.2.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [ dependencies = [
"percent-encoding", "percent-encoding",
] ]
@ -561,7 +697,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -624,22 +760,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]] [[package]]
name = "gltf-derive" name = "git_rev"
version = "1.4.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "438ffe1a5540d75403feaf23636b164e816e93f6f03131674722b3886ce32a57" checksum = "60884563ea313b5037683cd5d44f1e14e9cb07b08543756242a65887f9cff48e"
[[package]]
name = "gltf-derive"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51"
dependencies = [ dependencies = [
"inflections", "inflections",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
name = "gltf-json" name = "gltf-json"
version = "1.4.0" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "655951ba557f2bc69ea4b0799446bae281fa78efae6319968bdd2c3e9a06d8e1" checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14"
dependencies = [ dependencies = [
"gltf-derive", "gltf-derive",
"serde", "serde",
@ -684,6 +826,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.2" version = "0.3.2"
@ -774,7 +922,7 @@ dependencies = [
"futures-util", "futures-util",
"http 0.2.9", "http 0.2.9",
"hyper", "hyper",
"rustls 0.21.7", "rustls 0.21.12",
"tokio", "tokio",
"tokio-rustls 0.24.1", "tokio-rustls 0.24.1",
] ]
@ -803,10 +951,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "idna" name = "ident_case"
version = "0.4.0" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [ dependencies = [
"unicode-bidi", "unicode-bidi",
"unicode-normalization", "unicode-normalization",
@ -844,6 +998,12 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -879,18 +1039,22 @@ dependencies = [
[[package]] [[package]]
name = "kcl-lib" name = "kcl-lib"
version = "0.1.47" version = "0.1.55"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"approx", "approx",
"async-recursion", "async-recursion",
"async-trait", "async-trait",
"base64 0.22.1",
"bson", "bson",
"chrono", "chrono",
"clap",
"dashmap", "dashmap",
"databake", "databake",
"derive-docs", "derive-docs",
"form_urlencoded",
"futures", "futures",
"git_rev",
"gltf-json", "gltf-json",
"js-sys", "js-sys",
"kittycad", "kittycad",
@ -908,13 +1072,16 @@ dependencies = [
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
"toml",
"tower-lsp", "tower-lsp",
"ts-rs", "ts-rs",
"url",
"uuid", "uuid",
"validator",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"winnow", "winnow 0.5.40",
"zip", "zip",
] ]
@ -928,9 +1095,9 @@ dependencies = [
[[package]] [[package]]
name = "kittycad" name = "kittycad"
version = "0.2.63" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93a332250e08fd715ad3d5826e04d36da1c5bb42d0c1b1ff1f0598278b9ebf3c" checksum = "2c6e12eb45fd9a28c8e99dbdef54556246b39acee14e4aa6f0fc43636caa62d9"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -938,6 +1105,7 @@ dependencies = [
"bigdecimal", "bigdecimal",
"bytes", "bytes",
"chrono", "chrono",
"clap",
"data-encoding", "data-encoding",
"format_serde_error", "format_serde_error",
"futures", "futures",
@ -968,7 +1136,7 @@ checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1240,7 +1408,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.7.5", "regex-syntax 0.7.5",
"structmeta 0.2.0", "structmeta 0.2.0",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1254,14 +1422,14 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.8.2", "regex-syntax 0.8.2",
"structmeta 0.3.0", "structmeta 0.3.0",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.0" version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]] [[package]]
name = "phonenumber" name = "phonenumber"
@ -1301,7 +1469,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1348,9 +1516,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.78" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -1495,7 +1663,7 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls 0.21.7", "rustls 0.21.12",
"rustls-pemfile 1.0.3", "rustls-pemfile 1.0.3",
"serde", "serde",
"serde_json", "serde_json",
@ -1563,21 +1731,21 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.21.7" version = "0.21.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [ dependencies = [
"log", "log",
"ring 0.16.20", "ring 0.17.8",
"rustls-webpki 0.101.4", "rustls-webpki 0.101.7",
"sct", "sct",
] ]
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.22.2" version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
dependencies = [ dependencies = [
"log", "log",
"ring 0.17.8", "ring 0.17.8",
@ -1627,12 +1795,12 @@ checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7"
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.101.4" version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [ dependencies = [
"ring 0.16.20", "ring 0.17.8",
"untrusted 0.7.1", "untrusted 0.9.0",
] ]
[[package]] [[package]]
@ -1669,9 +1837,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.16" version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"bytes", "bytes",
@ -1686,14 +1854,14 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.16" version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde_derive_internals", "serde_derive_internals",
"syn 1.0.109", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1737,9 +1905,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.197" version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -1755,31 +1923,31 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.197" version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
name = "serde_derive_internals" name = "serde_derive_internals"
version = "0.26.0" version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 2.0.64",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.115" version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [ dependencies = [
"indexmap 2.2.3", "indexmap 2.2.3",
"itoa", "itoa",
@ -1795,7 +1963,16 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
]
[[package]]
name = "serde_spanned"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [
"serde",
] ]
[[package]] [[package]]
@ -1807,7 +1984,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1918,6 +2095,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "structmeta" name = "structmeta"
version = "0.2.0" version = "0.2.0"
@ -1927,7 +2110,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive 0.2.0", "structmeta-derive 0.2.0",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1939,7 +2122,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive 0.3.0", "structmeta-derive 0.3.0",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1950,7 +2133,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1961,7 +2144,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -1979,7 +2162,7 @@ version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [ dependencies = [
"heck", "heck 0.4.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
@ -2005,9 +2188,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.58" version = "2.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2028,7 +2211,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -2069,22 +2252,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.58" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.58" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -2157,7 +2340,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -2166,7 +2349,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [ dependencies = [
"rustls 0.21.7", "rustls 0.21.12",
"tokio", "tokio",
] ]
@ -2176,7 +2359,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
dependencies = [ dependencies = [
"rustls 0.22.2", "rustls 0.22.4",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
] ]
@ -2189,7 +2372,7 @@ checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
"rustls 0.22.2", "rustls 0.22.4",
"rustls-native-certs", "rustls-native-certs",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
@ -2211,6 +2394,40 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "toml"
version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c"
dependencies = [
"indexmap 2.2.3",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.8",
]
[[package]] [[package]]
name = "tower" name = "tower"
version = "0.4.13" version = "0.4.13"
@ -2263,7 +2480,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -2292,7 +2509,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
] ]
[[package]] [[package]]
@ -2316,8 +2533,10 @@ version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2cae1fc5d05d47aa24b64f9a4f7cba24cdc9187a2084dd97ac57bef5eccae6" checksum = "fc2cae1fc5d05d47aa24b64f9a4f7cba24cdc9187a2084dd97ac57bef5eccae6"
dependencies = [ dependencies = [
"chrono",
"thiserror", "thiserror",
"ts-rs-macros", "ts-rs-macros",
"url",
"uuid", "uuid",
] ]
@ -2330,7 +2549,7 @@ dependencies = [
"Inflector", "Inflector",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
"termcolor", "termcolor",
] ]
@ -2347,7 +2566,7 @@ dependencies = [
"httparse", "httparse",
"log", "log",
"rand", "rand",
"rustls 0.22.2", "rustls 0.22.4",
"rustls-pki-types", "rustls-pki-types",
"sha1", "sha1",
"thiserror", "thiserror",
@ -2397,6 +2616,12 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.7.1" version = "0.7.1"
@ -2411,9 +2636,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]] [[package]]
name = "url" name = "url"
version = "2.4.1" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna",
@ -2427,6 +2652,12 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.8.0" version = "1.8.0"
@ -2439,6 +2670,36 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "validator"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e"
dependencies = [
"idna",
"once_cell",
"regex",
"serde",
"serde_derive",
"serde_json",
"url",
"validator_derive",
]
[[package]]
name = "validator_derive"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55591299b7007f551ed1eb79a684af7672c19c3193fb9e0a31936987bb2438ec"
dependencies = [
"darling",
"once_cell",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.64",
]
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@ -2481,7 +2742,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2515,7 +2776,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.58", "syn 2.0.64",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2736,6 +2997,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winnow"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.50.0" version = "0.50.0"

View File

@ -1214,7 +1214,11 @@ impl CallExpression {
let func = memory.get(&fn_name, self.into())?; let func = memory.get(&fn_name, self.into())?;
let result = func let result = func
.call_fn(fn_args, memory.clone(), ctx.clone()) .call_fn(fn_args, memory.clone(), ctx.clone())
.await? .await
.map_err(|e| {
// Add the call expression to the source ranges.
e.add_source_ranges(vec![self.into()])
})?
.ok_or_else(|| { .ok_or_else(|| {
KclError::UndefinedValue(KclErrorDetails { KclError::UndefinedValue(KclErrorDetails {
message: format!("Result of user-defined function {} is undefined", fn_name), message: format!("Result of user-defined function {} is undefined", fn_name),

View File

@ -142,6 +142,25 @@ impl KclError {
new new
} }
pub fn add_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self {
let mut new = self.clone();
match &mut new {
KclError::Lexical(e) => e.source_ranges.extend(source_ranges),
KclError::Syntax(e) => e.source_ranges.extend(source_ranges),
KclError::Semantic(e) => e.source_ranges.extend(source_ranges),
KclError::Type(e) => e.source_ranges.extend(source_ranges),
KclError::Unimplemented(e) => e.source_ranges.extend(source_ranges),
KclError::Unexpected(e) => e.source_ranges.extend(source_ranges),
KclError::ValueAlreadyDefined(e) => e.source_ranges.extend(source_ranges),
KclError::UndefinedValue(e) => e.source_ranges.extend(source_ranges),
KclError::InvalidExpression(e) => e.source_ranges.extend(source_ranges),
KclError::Engine(e) => e.source_ranges.extend(source_ranges),
KclError::Internal(e) => e.source_ranges.extend(source_ranges),
}
new
}
} }
/// This is different than to_string() in that it will serialize the Error /// This is different than to_string() in that it will serialize the Error

View File

@ -498,14 +498,13 @@ impl Backend {
for (entry, value) in self.code_map.inner().await.iter() { for (entry, value) in self.code_map.inner().await.iter() {
let file_name = entry.replace("file://", "").to_string(); let file_name = entry.replace("file://", "").to_string();
let options = zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Stored); let options = zip::write::SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored);
zip.start_file(file_name, options)?; zip.start_file(file_name, options)?;
zip.write_all(value)?; zip.write_all(value)?;
} }
// Apply the changes you've made. // Apply the changes you've made.
// Dropping the `ZipWriter` will have the same effect, but may silently fail // Dropping the `ZipWriter` will have the same effect, but may silently fail
zip.finish()?; zip.finish()?;
drop(zip);
Ok(buf) Ok(buf)
} }

View File

@ -1,5 +1,6 @@
//! Types for interacting with files in projects. //! Types for interacting with files in projects.
#[cfg(not(target_arch = "wasm32"))]
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
@ -7,7 +8,7 @@ use parse_display::{Display, FromStr};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::settings::types::{Configuration, DEFAULT_PROJECT_KCL_FILE}; use crate::settings::types::Configuration;
/// State management for the application. /// State management for the application.
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)] #[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)]
@ -48,7 +49,7 @@ impl ProjectState {
.map_err(|e| anyhow::anyhow!("Error loading project from path {}: {:?}", source_path.display(), e))?; .map_err(|e| anyhow::anyhow!("Error loading project from path {}: {:?}", source_path.display(), e))?;
// Check if we have a main.kcl file in the project. // Check if we have a main.kcl file in the project.
let project_file = source_path.join(DEFAULT_PROJECT_KCL_FILE); let project_file = source_path.join(crate::settings::types::DEFAULT_PROJECT_KCL_FILE);
if !project_file.exists() { if !project_file.exists() {
// Create the default file in the project. // Create the default file in the project.
@ -93,6 +94,44 @@ impl ProjectState {
.await .await
.map_err(|e| anyhow::anyhow!("Error loading project from path {}: {:?}", source_path.display(), e))?; .map_err(|e| anyhow::anyhow!("Error loading project from path {}: {:?}", source_path.display(), e))?;
// If we got a import model file, we need to check if we have a file in the project for
// this import model.
if crate::settings::utils::IMPORT_FILE_EXTENSIONS.contains(&ext) {
let import_file_name = source_path
.file_name()
.ok_or_else(|| anyhow::anyhow!("Error getting the file name of the file: {}", source_path.display()))?
.to_string_lossy()
.to_string();
// Check if we have a file in the project for this import model.
let kcl_wrapper_filename = format!("{}.kcl", import_file_name);
let kcl_wrapper_file_path = parent.join(&kcl_wrapper_filename);
if !kcl_wrapper_file_path.exists() {
// Create the file in the project.
// With the default import content.
tokio::fs::write(
&kcl_wrapper_file_path,
format!(
r#"// This file was automatically generated by the application when you
// double-clicked on the model file.
// You can edit this file to add your own content.
// But we recommend you keep the import statement as it is.
// For more information on the import statement, see the documentation at:
// https://zoo.dev/docs/kcl/import
const model = import("{}")"#,
import_file_name
)
.as_bytes(),
)
.await?;
}
return Ok(ProjectState {
project,
current_file: Some(kcl_wrapper_file_path.display().to_string()),
});
}
Ok(ProjectState { Ok(ProjectState {
project, project,
current_file: Some(source_path.display().to_string()), current_file: Some(source_path.display().to_string()),
@ -209,6 +248,8 @@ pub struct Project {
#[serde(default)] #[serde(default)]
#[ts(type = "number")] #[ts(type = "number")]
pub directory_count: u64, pub directory_count: u64,
/// The default file to open on load.
pub default_file: String,
} }
impl Project { impl Project {
@ -228,12 +269,13 @@ impl Project {
} }
let file = crate::settings::utils::walk_dir(&path).await?; let file = crate::settings::utils::walk_dir(&path).await?;
let metadata = std::fs::metadata(path).ok().map(|m| m.into()); let metadata = std::fs::metadata(&path).ok().map(|m| m.into());
let mut project = Self { let mut project = Self {
file, file: file.clone(),
metadata, metadata,
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file: get_default_kcl_file_for_dir(path, file).await?,
}; };
project.populate_kcl_file_count()?; project.populate_kcl_file_count()?;
project.populate_directory_count()?; project.populate_directory_count()?;
@ -271,6 +313,40 @@ impl Project {
} }
} }
/// Get the default KCL file for a directory.
/// This determines what the default file to open is.
#[cfg(not(target_arch = "wasm32"))]
#[async_recursion::async_recursion]
pub async fn get_default_kcl_file_for_dir<P>(dir: P, file: FileEntry) -> Result<String>
where
P: AsRef<Path> + Send,
{
// Make sure the dir is a directory.
if !dir.as_ref().is_dir() {
return Err(anyhow::anyhow!("Path `{}` is not a directory", dir.as_ref().display()));
}
let default_file = dir.as_ref().join(crate::settings::types::DEFAULT_PROJECT_KCL_FILE);
if !default_file.exists() {
// Find a kcl file in the directory.
if let Some(children) = file.children {
for entry in children.iter() {
if entry.name.ends_with(".kcl") {
return Ok(dir.as_ref().join(&entry.name).display().to_string());
} else if entry.children.is_some() {
// Recursively find a kcl file in the directory.
return get_default_kcl_file_for_dir(entry.path.clone(), entry.clone()).await;
}
}
}
// If we didn't find a kcl file, create one.
tokio::fs::write(&default_file, vec![]).await?;
}
Ok(default_file.display().to_string())
}
/// Information about a file or directory. /// Information about a file or directory.
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)] #[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq)]
#[ts(export)] #[ts(export)]
@ -550,4 +626,100 @@ mod tests {
} }
); );
} }
#[test]
fn test_project_route_from_route_non_main_file() {
let mut configuration = crate::settings::types::Configuration::default();
configuration.settings.project.directory =
std::path::PathBuf::from("/Users/macinatormax/Documents/kittycad-modeling-projects");
let route = "/Users/macinatormax/Documents/kittycad-modeling-projects/assembly/thing.kcl";
let state = super::ProjectRoute::from_route(&configuration, route).unwrap();
assert_eq!(
state,
super::ProjectRoute {
project_name: Some("assembly".to_string()),
project_path: "/Users/macinatormax/Documents/kittycad-modeling-projects/assembly".to_string(),
current_file_name: Some("thing.kcl".to_string()),
current_file_path: Some(
"/Users/macinatormax/Documents/kittycad-modeling-projects/assembly/thing.kcl".to_string()
),
}
);
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_non_exist() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(default_file, dir.join("main.kcl").display().to_string());
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_main_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("main.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(default_file, dir.join("main.kcl").display().to_string());
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_thing_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("thing.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(default_file, dir.join("thing.kcl").display().to_string());
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_nested_main_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::create_dir_all(dir.join("assembly")).unwrap();
std::fs::write(dir.join("assembly").join("main.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(
default_file,
dir.join("assembly").join("main.kcl").display().to_string()
);
std::fs::remove_dir_all(dir).unwrap();
}
#[tokio::test]
async fn test_default_kcl_file_for_dir_nested_thing_kcl() {
let name = format!("kittycad-modeling-projects-{}", uuid::Uuid::new_v4());
let dir = std::env::temp_dir().join(&name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::create_dir_all(dir.join("assembly")).unwrap();
std::fs::write(dir.join("assembly").join("thing.kcl"), vec![]).unwrap();
let file = crate::settings::utils::walk_dir(&dir).await.unwrap();
let default_file = super::get_default_kcl_file_for_dir(&dir, file).await.unwrap();
assert_eq!(
default_file,
dir.join("assembly").join("thing.kcl").display().to_string()
);
std::fs::remove_dir_all(dir).unwrap();
}
} }

View File

@ -109,6 +109,7 @@ impl Configuration {
// Because we just created it and it's empty. // Because we just created it and it's empty.
children: None, children: None,
}, },
default_file: project_file.to_string_lossy().to_string(),
metadata: Some(tokio::fs::metadata(&project_dir).await?.into()), metadata: Some(tokio::fs::metadata(&project_dir).await?.into()),
kcl_file_count: 1, kcl_file_count: 1,
directory_count: 0, directory_count: 0,
@ -130,7 +131,13 @@ impl Configuration {
continue; continue;
} }
projects.push(self.get_project_info(&e.path().display().to_string()).await?); // Make sure the project has at least one kcl file in it.
let project = self.get_project_info(&e.path().display().to_string()).await?;
if project.kcl_file_count == 0 {
continue;
}
projects.push(project);
} }
Ok(projects) Ok(projects)
@ -150,11 +157,14 @@ impl Configuration {
return Err(anyhow::anyhow!("Project path is not a directory: {}", project_path)); return Err(anyhow::anyhow!("Project path is not a directory: {}", project_path));
} }
let walked = crate::settings::utils::walk_dir(project_dir).await?;
let mut project = crate::settings::types::file::Project { let mut project = crate::settings::types::file::Project {
file: crate::settings::utils::walk_dir(project_dir).await?, file: walked.clone(),
metadata: Some(tokio::fs::metadata(&project_dir).await?.into()), metadata: Some(tokio::fs::metadata(&project_dir).await?.into()),
kcl_file_count: 0, kcl_file_count: 0,
directory_count: 0, directory_count: 0,
default_file: crate::settings::types::file::get_default_kcl_file_for_dir(project_dir, walked).await?,
}; };
// Populate the number of KCL files in the project. // Populate the number of KCL files in the project.

View File

@ -8,14 +8,21 @@ use clap::ValueEnum;
use crate::settings::types::file::FileEntry; use crate::settings::types::file::FileEntry;
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref RELEVANT_EXTENSIONS: Vec<String> = {
let mut relevant_extensions = vec!["kcl".to_string(), "stp".to_string(), "glb".to_string(), "fbxb".to_string()]; pub static ref IMPORT_FILE_EXTENSIONS: Vec<String> = {
let mut import_file_extensions = vec!["stp".to_string(), "glb".to_string(), "fbxb".to_string()];
let named_extensions = kittycad::types::FileImportFormat::value_variants() let named_extensions = kittycad::types::FileImportFormat::value_variants()
.iter() .iter()
.map(|x| format!("{}", x)) .map(|x| format!("{}", x))
.collect::<Vec<String>>(); .collect::<Vec<String>>();
// Add all the default import formats. // Add all the default import formats.
relevant_extensions.extend_from_slice(&named_extensions); import_file_extensions.extend_from_slice(&named_extensions);
import_file_extensions
};
pub static ref RELEVANT_EXTENSIONS: Vec<String> = {
let mut relevant_extensions = IMPORT_FILE_EXTENSIONS.clone();
relevant_extensions.push("kcl".to_string());
relevant_extensions relevant_extensions
}; };
} }
@ -26,6 +33,16 @@ pub async fn walk_dir<P>(dir: P) -> Result<FileEntry>
where where
P: AsRef<Path> + Send, P: AsRef<Path> + Send,
{ {
// Make sure the path is a directory.
if !dir.as_ref().is_dir() {
return Err(anyhow::anyhow!("Path `{}` is not a directory", dir.as_ref().display()));
}
// Make sure the directory exists.
if !dir.as_ref().exists() {
return Err(anyhow::anyhow!("Directory `{}` does not exist", dir.as_ref().display()));
}
let mut entry = FileEntry { let mut entry = FileEntry {
name: dir name: dir
.as_ref() .as_ref()

View File

@ -129,27 +129,27 @@ pub async fn import(args: Args) -> Result<MemoryItem, KclError> {
/// not in browser. /// not in browser.
/// ///
/// ```no_run /// ```no_run
/// const model = import("thing.obj") /// const model = import("tests/inputs/cube.obj")
/// ``` /// ```
/// ///
/// ```no_run /// ```no_run
/// const model = import("cube.obj", {type: "obj", units: "m"}) /// const model = import("tests/inputs/cube.obj", {type: "obj", units: "m"})
/// ``` /// ```
/// ///
/// ```no_run /// ```no_run
/// const model = import("my_model.gltf") /// const model = import("tests/inputs/cube.gltf")
/// ``` /// ```
/// ///
/// ```no_run /// ```no_run
/// const model = import("my_model.sldprt") /// const model = import("tests/inputs/cube.sldprt")
/// ``` /// ```
/// ///
/// ```no_run /// ```no_run
/// const model = import("my_model.step") /// const model = import("tests/inputs/cube.step")
/// ``` /// ```
#[stdlib { #[stdlib {
name = "import", name = "import",
tags = ["norun"], tags = [],
}] }]
async fn inner_import( async fn inner_import(
file_path: String, file_path: String,
@ -163,6 +163,9 @@ async fn inner_import(
})); }));
} }
//print the current working directory
println!("Current working directory: {:?}", std::env::current_dir().unwrap());
// Make sure the file exists. // Make sure the file exists.
if !args.ctx.fs.exists(&file_path, args.source_range).await? { if !args.ctx.fs.exists(&file_path, args.source_range).await? {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {

View File

@ -239,7 +239,7 @@ pub async fn max(args: Args) -> Result<MemoryItem, KclError> {
tags = ["math"], tags = ["math"],
}] }]
fn inner_max(args: Vec<f64>) -> f64 { fn inner_max(args: Vec<f64>) -> f64 {
let mut max = std::f64::MAX; let mut max = std::f64::MIN;
for arg in args.iter() { for arg in args.iter() {
if *arg > max { if *arg > max {
max = *arg; max = *arg;
@ -533,3 +533,38 @@ pub async fn to_degrees(args: Args) -> Result<MemoryItem, KclError> {
fn inner_to_degrees(num: f64) -> Result<f64, KclError> { fn inner_to_degrees(num: f64) -> Result<f64, KclError> {
Ok(num.to_degrees()) Ok(num.to_degrees())
} }
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_inner_max() {
let nums = vec![4.0, 5.0, 6.0];
let result = inner_max(nums);
assert_eq!(result, 6.0);
}
#[test]
fn test_inner_max_with_neg() {
let nums = vec![4.0, -5.0];
let result = inner_max(nums);
assert_eq!(result, 4.0);
}
#[test]
fn test_inner_min() {
let nums = vec![4.0, 5.0, 6.0];
let result = inner_min(nums);
assert_eq!(result, 4.0);
}
#[test]
fn test_inner_min_with_neg() {
let nums = vec![4.0, -5.0];
let result = inner_min(nums);
assert_eq!(result, -5.0);
}
}

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),
@ -1058,9 +1061,7 @@ layout: manual
fn_docs.push_str("\n```\n\n"); fn_docs.push_str("\n```\n\n");
// If the function has tags, we should add them to the docs. // If the function has tags, we should add them to the docs.
let mut tags = internal_fn.tags().clone(); let tags = internal_fn.tags().clone();
// Remove norun tag from the list of tags.
tags.retain(|tag| tag != "norun");
if !tags.is_empty() { if !tags.is_empty() {
fn_docs.push_str("### Tags\n\n"); fn_docs.push_str("### Tags\n\n");
for tag in tags { for tag in tags {
@ -1079,9 +1080,7 @@ layout: manual
// If this is not a "utilities" function, // If this is not a "utilities" function,
// we should add the image to the docs. // we should add the image to the docs.
if !internal_fn.tags().contains(&"utilities".to_string()) if !internal_fn.tags().contains(&"utilities".to_string()) {
&& !internal_fn.tags().contains(&"norun".to_string())
{
// Get the path to this specific rust file. // Get the path to this specific rust file.
let dir = env!("CARGO_MANIFEST_DIR"); let dir = env!("CARGO_MANIFEST_DIR");

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::{
@ -995,27 +995,35 @@ async fn start_sketch_on_face(
args: Args, args: Args,
) -> Result<Box<Face>, KclError> { ) -> Result<Box<Face>, KclError> {
let extrude_plane_id = match tag { let extrude_plane_id = match tag {
SketchOnFaceTag::String(ref s) => extrude_group SketchOnFaceTag::String(ref s) => {
.value if s.is_empty() {
.iter() return Err(KclError::Type(KclErrorDetails {
.find_map(|extrude_surface| match extrude_surface { message: "Expected a non-empty tag for the face to sketch on".to_string(),
ExtrudeSurface::ExtrudePlane(extrude_plane) if extrude_plane.name == *s => {
Some(Ok(extrude_plane.face_id))
}
ExtrudeSurface::ExtrudeArc(extrude_arc) if extrude_arc.name == *s => {
Some(Err(KclError::Type(KclErrorDetails {
message: format!("Cannot sketch on a non-planar surface: `{}`", tag),
source_ranges: vec![args.source_range],
})))
}
ExtrudeSurface::ExtrudePlane(_) | ExtrudeSurface::ExtrudeArc(_) => None,
})
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a face with the tag `{}`", tag),
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
}));
}
extrude_group
.value
.iter()
.find_map(|extrude_surface| match extrude_surface {
ExtrudeSurface::ExtrudePlane(extrude_plane) if extrude_plane.name == *s => {
Some(Ok(extrude_plane.face_id))
}
ExtrudeSurface::ExtrudeArc(extrude_arc) if extrude_arc.name == *s => {
Some(Err(KclError::Type(KclErrorDetails {
message: format!("Cannot sketch on a non-planar surface: `{}`", tag),
source_ranges: vec![args.source_range],
})))
}
ExtrudeSurface::ExtrudePlane(_) | ExtrudeSurface::ExtrudeArc(_) => None,
}) })
})??, .ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a face with the tag `{}`", tag),
source_ranges: vec![args.source_range],
})
})??
}
SketchOnFaceTag::StartOrEnd(StartOrEnd::Start) => extrude_group.start_cap_id.ok_or_else(|| { SketchOnFaceTag::StartOrEnd(StartOrEnd::Start) => extrude_group.start_cap_id.ok_or_else(|| {
KclError::Type(KclErrorDetails { KclError::Type(KclErrorDetails {
message: "Expected a start face to sketch on".to_string(), message: "Expected a start face to sketch on".to_string(),
@ -1206,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()?;

View File

@ -0,0 +1,108 @@
{
"asset": {
"generator": "Khronos glTF Blender I/O v3.4.50",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"name": "Scene",
"nodes": [0]
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"materials": [
{
"doubleSided": true,
"name": "Material",
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929, 0.800000011920929, 0.800000011920929, 1
],
"metallicFactor": 0,
"roughnessFactor": 0.5
}
}
],
"meshes": [
{
"name": "Cube",
"primitives": [
{
"attributes": {
"POSITION": 0,
"TEXCOORD_0": 1,
"NORMAL": 2
},
"indices": 3,
"material": 0
}
]
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 24,
"max": [1, 1, 1],
"min": [-1, -1, -1],
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 24,
"type": "VEC2"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 24,
"type": "VEC3"
},
{
"bufferView": 3,
"componentType": 5123,
"count": 36,
"type": "SCALAR"
}
],
"bufferViews": [
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 0,
"target": 34962
},
{
"buffer": 0,
"byteLength": 192,
"byteOffset": 288,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 480,
"target": 34962
},
{
"buffer": 0,
"byteLength": 72,
"byteOffset": 768,
"target": 34963
}
],
"buffers": [
{
"byteLength": 840,
"uri": "data:application/octet-stream;base64,AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAQD8AACA/AABAPwAAYD8AAAA/AAAAPgAAAD8AAMA+AABAPwAAwD4AAEA/AAAgPwAAAAAAACA/AACAPwAAYD8AAIA+AAAAPgAAgD4AAMA+AAAAAAAAwD4AAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAQAOABQAAQAUAAcACgAGABIACgASABYAFwATAAwAFwAMABAADwADAAkADwAJABUABQACAAgABQAIAAsAEQANAAAAEQAAAAQA"
}
]
}

View File

@ -0,0 +1,12 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl Material
Ns 359.999993
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

View File

@ -0,0 +1,40 @@
# Blender v3.2.2 OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 1.000000 -1.000000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.125000 0.750000
vn 0.0000 0.0000 1.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
usemtl Material
s off
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/4/2 7/6/2 8/7/2
f 8/8/3 7/9/3 5/10/3 6/11/3
f 6/12/4 2/13/4 4/5/4 8/14/4
f 2/13/5 1/1/5 3/4/5 4/5/5
f 6/11/6 5/10/6 1/1/6 2/13/6

Binary file not shown.

View File

@ -0,0 +1,254 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION (( 'STEP AP203' ),
'1' );
FILE_NAME ('Cube_1m.STEP',
'2023-07-31T15:10:19',
( '' ),
( '' ),
'SwSTEP 2.0',
'SolidWorks 2023',
'' );
FILE_SCHEMA (( 'CONFIG_CONTROL_DESIGN' ));
ENDSEC;
DATA;
#1 = AXIS2_PLACEMENT_3D ( 'NONE', #133, #116, #72 ) ;
#2 =( LENGTH_UNIT ( ) NAMED_UNIT ( * ) SI_UNIT ( .MILLI., .METRE. ) );
#3 = FACE_OUTER_BOUND ( 'NONE', #99, .T. ) ;
#4 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#5 = VECTOR ( 'NONE', #233, 1000.000000000000000 ) ;
#6 = ORIENTED_EDGE ( 'NONE', *, *, #15, .T. ) ;
#7 = DIRECTION ( 'NONE', ( -0.000000000000000000, -1.000000000000000000, -0.000000000000000000 ) ) ;
#8 = ORIENTED_EDGE ( 'NONE', *, *, #75, .T. ) ;
#9 = VECTOR ( 'NONE', #205, 1000.000000000000000 ) ;
#10 = LOCAL_TIME ( 11, 10, 19.00000000000000000, #88 ) ;
#11 = PLANE ( 'NONE', #220 ) ;
#12 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, 500.0000000000000000 ) ) ;
#13 = DIRECTION ( 'NONE', ( -0.000000000000000000, -1.000000000000000000, -0.000000000000000000 ) ) ;
#14 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#15 = EDGE_CURVE ( 'NONE', #40, #58, #139, .T. ) ;
#16 = CALENDAR_DATE ( 2023, 31, 7 ) ;
#17 = AXIS2_PLACEMENT_3D ( 'NONE', #175, #73, #126 ) ;
#18 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#19 = PLANE ( 'NONE', #145 ) ;
#20 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#21 =( GEOMETRIC_REPRESENTATION_CONTEXT ( 3 ) GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT ( ( #152 ) ) GLOBAL_UNIT_ASSIGNED_CONTEXT ( ( #2, #168, #174 ) ) REPRESENTATION_CONTEXT ( 'NONE', 'WORKASPACE' ) );
#22 = FACE_OUTER_BOUND ( 'NONE', #137, .T. ) ;
#23 = PRODUCT_DEFINITION ( 'UNKNOWN', '', #51, #86 ) ;
#24 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, -1.000000000000000000 ) ) ;
#25 = APPLICATION_PROTOCOL_DEFINITION ( 'international standard', 'config_control_design', 1994, #59 ) ;
#26 = PLANE ( 'NONE', #17 ) ;
#27 = EDGE_LOOP ( 'NONE', ( #141, #8, #121, #123 ) ) ;
#28 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#29 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 0.000000000000000000, -500.0000000000000000 ) ) ;
#30 = FACE_OUTER_BOUND ( 'NONE', #78, .T. ) ;
#31 = LINE ( 'NONE', #183, #179 ) ;
#32 = PLANE ( 'NONE', #173 ) ;
#33 = VECTOR ( 'NONE', #44, 1000.000000000000000 ) ;
#34 = DATE_AND_TIME ( #16, #224 ) ;
#35 = ADVANCED_FACE ( 'NONE', ( #198 ), #26, .T. ) ;
#36 = CALENDAR_DATE ( 2023, 31, 7 ) ;
#37 = VECTOR ( 'NONE', #61, 1000.000000000000000 ) ;
#38 = CC_DESIGN_APPROVAL ( #210, ( #51 ) ) ;
#39 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, 500.0000000000000000 ) ) ;
#40 = VERTEX_POINT ( 'NONE', #98 ) ;
#41 = ORIENTED_EDGE ( 'NONE', *, *, #119, .F. ) ;
#42 = ORIENTED_EDGE ( 'NONE', *, *, #69, .T. ) ;
#43 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT ( #167, #188, ( #180 ) ) ;
#44 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 1.000000000000000000 ) ) ;
#45 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 0.000000000000000000, 500.0000000000000000 ) ) ;
#46 = APPLICATION_CONTEXT ( 'configuration controlled 3d designs of mechanical parts and assemblies' ) ;
#47 = LINE ( 'NONE', #203, #101 ) ;
#48 = ORIENTED_EDGE ( 'NONE', *, *, #144, .F. ) ;
#49 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 0.000000000000000000, 500.0000000000000000 ) ) ;
#50 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 1000.000000000000000, 500.0000000000000000 ) ) ;
#51 = PRODUCT_DEFINITION_FORMATION_WITH_SPECIFIED_SOURCE ( 'ANY', '', #68, .NOT_KNOWN. ) ;
#52 = DATE_AND_TIME ( #110, #186 ) ;
#53 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT ( #192, #92, ( #68 ) ) ;
#54 = DATE_AND_TIME ( #117, #90 ) ;
#55 = VECTOR ( 'NONE', #209, 1000.000000000000000 ) ;
#56 = PLANE ( 'NONE', #129 ) ;
#57 = VERTEX_POINT ( 'NONE', #127 ) ;
#58 = VERTEX_POINT ( 'NONE', #49 ) ;
#59 = APPLICATION_CONTEXT ( 'configuration controlled 3d designs of mechanical parts and assemblies' ) ;
#60 = EDGE_CURVE ( 'NONE', #57, #80, #185, .T. ) ;
#61 = DIRECTION ( 'NONE', ( -0.000000000000000000, -1.000000000000000000, -0.000000000000000000 ) ) ;
#62 = ORIENTED_EDGE ( 'NONE', *, *, #211, .F. ) ;
#63 = LINE ( 'NONE', #232, #236 ) ;
#64 = ORIENTED_EDGE ( 'NONE', *, *, #96, .F. ) ;
#65 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 0.000000000000000000, -500.0000000000000000 ) ) ;
#66 = PLANE ( 'NONE', #70 ) ;
#67 = CLOSED_SHELL ( 'NONE', ( #226, #164, #169, #234, #35, #219 ) ) ;
#68 = PRODUCT ( 'Cube_1m', 'Cube_1m', '', ( #155 ) ) ;
#69 = EDGE_CURVE ( 'NONE', #80, #120, #31, .T. ) ;
#70 = AXIS2_PLACEMENT_3D ( 'NONE', #138, #105, #217 ) ;
#71 = DATE_AND_TIME ( #172, #194 ) ;
#72 = DIRECTION ( 'NONE', ( 1.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#73 = DIRECTION ( 'NONE', ( 0.000000000000000000, 1.000000000000000000, 0.000000000000000000 ) ) ;
#74 = VERTEX_POINT ( 'NONE', #124 ) ;
#75 = EDGE_CURVE ( 'NONE', #80, #135, #81, .T. ) ;
#76 = LINE ( 'NONE', #50, #170 ) ;
#77 = CC_DESIGN_APPROVAL ( #166, ( #23 ) ) ;
#78 = EDGE_LOOP ( 'NONE', ( #97, #199, #230, #42 ) ) ;
#79 = CARTESIAN_POINT ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#80 = VERTEX_POINT ( 'NONE', #28 ) ;
#81 = LINE ( 'NONE', #103, #85 ) ;
#82 = DIRECTION ( 'NONE', ( -1.000000000000000000, -0.000000000000000000, -0.000000000000000000 ) ) ;
#83 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT ( #93, #115, ( #23 ) ) ;
#84 = APPROVAL_DATE_TIME ( #112, #210 ) ;
#85 = VECTOR ( 'NONE', #82, 1000.000000000000000 ) ;
#86 = DESIGN_CONTEXT ( 'detailed design', #59, 'design' ) ;
#87 = APPROVAL_STATUS ( 'not_yet_approved' ) ;
#88 = COORDINATED_UNIVERSAL_TIME_OFFSET ( 5, 0, .BEHIND. ) ;
#89 = COORDINATED_UNIVERSAL_TIME_OFFSET ( 5, 0, .BEHIND. ) ;
#90 = LOCAL_TIME ( 11, 10, 19.00000000000000000, #154 ) ;
#91 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#92 = PERSON_AND_ORGANIZATION_ROLE ( 'design_owner' ) ;
#93 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#94 = APPLICATION_PROTOCOL_DEFINITION ( 'international standard', 'config_control_design', 1994, #46 ) ;
#95 = APPROVAL ( #87, 'UNSPECIFIED' ) ;
#96 = EDGE_CURVE ( 'NONE', #74, #57, #162, .T. ) ;
#97 = ORIENTED_EDGE ( 'NONE', *, *, #144, .T. ) ;
#98 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 0.000000000000000000, 500.0000000000000000 ) ) ;
#99 = EDGE_LOOP ( 'NONE', ( #6, #125, #64, #118 ) ) ;
#100 = DIRECTION ( 'NONE', ( 1.000000000000000000, 0.000000000000000000, -0.000000000000000000 ) ) ;
#101 = VECTOR ( 'NONE', #204, 1000.000000000000000 ) ;
#102 = EDGE_LOOP ( 'NONE', ( #178, #202, #41, #48 ) ) ;
#103 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#104 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#105 = DIRECTION ( 'NONE', ( 1.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#106 = PRODUCT_RELATED_PRODUCT_CATEGORY ( 'detail', '', ( #68 ) ) ;
#107 = EDGE_CURVE ( 'NONE', #135, #215, #140, .T. ) ;
#108 = CC_DESIGN_APPROVAL ( #95, ( #180 ) ) ;
#109 = SHAPE_DEFINITION_REPRESENTATION ( #146, #222 ) ;
#110 = CALENDAR_DATE ( 2023, 31, 7 ) ;
#111 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#112 = DATE_AND_TIME ( #36, #10 ) ;
#113 = APPROVAL_PERSON_ORGANIZATION ( #18, #95, #130 ) ;
#114 = APPROVAL_PERSON_ORGANIZATION ( #111, #210, #132 ) ;
#115 = PERSON_AND_ORGANIZATION_ROLE ( 'creator' ) ;
#116 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 1.000000000000000000 ) ) ;
#117 = CALENDAR_DATE ( 2023, 31, 7 ) ;
#118 = ORIENTED_EDGE ( 'NONE', *, *, #128, .T. ) ;
#119 = EDGE_CURVE ( 'NONE', #215, #40, #63, .T. ) ;
#120 = VERTEX_POINT ( 'NONE', #159 ) ;
#121 = ORIENTED_EDGE ( 'NONE', *, *, #211, .T. ) ;
#122 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 1.000000000000000000 ) ) ;
#123 = ORIENTED_EDGE ( 'NONE', *, *, #96, .T. ) ;
#124 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, 500.0000000000000000 ) ) ;
#125 = ORIENTED_EDGE ( 'NONE', *, *, #189, .F. ) ;
#126 = DIRECTION ( 'NONE', ( 0.000000000000000000, -0.000000000000000000, 1.000000000000000000 ) ) ;
#127 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 1000.000000000000000, 500.0000000000000000 ) ) ;
#128 = EDGE_CURVE ( 'NONE', #74, #40, #142, .T. ) ;
#129 = AXIS2_PLACEMENT_3D ( 'NONE', #4, #195, #171 ) ;
#130 = APPROVAL_ROLE ( '' ) ;
#131 = APPROVAL_DATE_TIME ( #71, #166 ) ;
#132 = APPROVAL_ROLE ( '' ) ;
#133 = CARTESIAN_POINT ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#134 = PERSON ( 'UNSPECIFIED', 'UNSPECIFIED', 'UNSPECIFIED', ('UNSPECIFIED'), ('UNSPECIFIED'), ('UNSPECIFIED') ) ;
#135 = VERTEX_POINT ( 'NONE', #214 ) ;
#136 = APPROVAL_PERSON_ORGANIZATION ( #91, #166, #151 ) ;
#137 = EDGE_LOOP ( 'NONE', ( #158, #176, #157, #212 ) ) ;
#138 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#139 = LINE ( 'NONE', #45, #55 ) ;
#140 = LINE ( 'NONE', #177, #37 ) ;
#141 = ORIENTED_EDGE ( 'NONE', *, *, #60, .T. ) ;
#142 = LINE ( 'NONE', #231, #193 ) ;
#143 = FACE_OUTER_BOUND ( 'NONE', #227, .T. ) ;
#144 = EDGE_CURVE ( 'NONE', #120, #215, #47, .T. ) ;
#145 = AXIS2_PLACEMENT_3D ( 'NONE', #39, #24, #207 ) ;
#146 = PRODUCT_DEFINITION_SHAPE ( 'NONE', 'NONE', #23 ) ;
#147 = PERSON_AND_ORGANIZATION_ROLE ( 'creator' ) ;
#148 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT ( #165, #147, ( #51 ) ) ;
#149 = DATE_TIME_ROLE ( 'classification_date' ) ;
#150 = EDGE_CURVE ( 'NONE', #58, #120, #163, .T. ) ;
#151 = APPROVAL_ROLE ( '' ) ;
#152 = UNCERTAINTY_MEASURE_WITH_UNIT (LENGTH_MEASURE( 1.000000000000000082E-05 ), #2, 'distance_accuracy_value', 'NONE');
#153 = CC_DESIGN_SECURITY_CLASSIFICATION ( #180, ( #51 ) ) ;
#154 = COORDINATED_UNIVERSAL_TIME_OFFSET ( 5, 0, .BEHIND. ) ;
#155 = MECHANICAL_CONTEXT ( 'NONE', #46, 'mechanical' ) ;
#156 = VECTOR ( 'NONE', #229, 1000.000000000000000 ) ;
#157 = ORIENTED_EDGE ( 'NONE', *, *, #60, .F. ) ;
#158 = ORIENTED_EDGE ( 'NONE', *, *, #150, .T. ) ;
#159 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 0.000000000000000000, -500.0000000000000000 ) ) ;
#160 = ORIENTED_EDGE ( 'NONE', *, *, #119, .T. ) ;
#161 = DIRECTION ( 'NONE', ( 0.000000000000000000, 1.000000000000000000, 0.000000000000000000 ) ) ;
#162 = LINE ( 'NONE', #12, #9 ) ;
#163 = LINE ( 'NONE', #65, #5 ) ;
#164 = ADVANCED_FACE ( 'NONE', ( #30 ), #32, .F. ) ;
#165 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#166 = APPROVAL ( #196, 'UNSPECIFIED' ) ;
#167 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#168 =( NAMED_UNIT ( * ) PLANE_ANGLE_UNIT ( ) SI_UNIT ( $, .RADIAN. ) );
#169 = ADVANCED_FACE ( 'NONE', ( #143 ), #66, .F. ) ;
#170 = VECTOR ( 'NONE', #7, 1000.000000000000000 ) ;
#171 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 1.000000000000000000 ) ) ;
#172 = CALENDAR_DATE ( 2023, 31, 7 ) ;
#173 = AXIS2_PLACEMENT_3D ( 'NONE', #104, #184, #100 ) ;
#174 =( NAMED_UNIT ( * ) SI_UNIT ( $, .STERADIAN. ) SOLID_ANGLE_UNIT ( ) );
#175 = CARTESIAN_POINT ( 'NONE', ( 0.000000000000000000, 1000.000000000000000, 0.000000000000000000 ) ) ;
#176 = ORIENTED_EDGE ( 'NONE', *, *, #69, .F. ) ;
#177 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#178 = ORIENTED_EDGE ( 'NONE', *, *, #150, .F. ) ;
#179 = VECTOR ( 'NONE', #13, 1000.000000000000000 ) ;
#180 = SECURITY_CLASSIFICATION ( '', '', #223 ) ;
#181 = FACE_OUTER_BOUND ( 'NONE', #102, .T. ) ;
#182 = ORIENTED_EDGE ( 'NONE', *, *, #107, .T. ) ;
#183 = CARTESIAN_POINT ( 'NONE', ( 500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#184 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, 1.000000000000000000 ) ) ;
#185 = LINE ( 'NONE', #14, #156 ) ;
#186 = LOCAL_TIME ( 11, 10, 19.00000000000000000, #221 ) ;
#187 = CC_DESIGN_DATE_AND_TIME_ASSIGNMENT ( #54, #197, ( #23 ) ) ;
#188 = PERSON_AND_ORGANIZATION_ROLE ( 'classification_officer' ) ;
#189 = EDGE_CURVE ( 'NONE', #57, #58, #76, .T. ) ;
#190 = APPROVAL_STATUS ( 'not_yet_approved' ) ;
#191 = PERSON_AND_ORGANIZATION_ROLE ( 'design_supplier' ) ;
#192 = PERSON_AND_ORGANIZATION ( #134, #228 ) ;
#193 = VECTOR ( 'NONE', #216, 1000.000000000000000 ) ;
#194 = LOCAL_TIME ( 11, 10, 19.00000000000000000, #208 ) ;
#195 = DIRECTION ( 'NONE', ( -1.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#196 = APPROVAL_STATUS ( 'not_yet_approved' ) ;
#197 = DATE_TIME_ROLE ( 'creation_date' ) ;
#198 = FACE_OUTER_BOUND ( 'NONE', #27, .T. ) ;
#199 = ORIENTED_EDGE ( 'NONE', *, *, #107, .F. ) ;
#200 = ORIENTED_EDGE ( 'NONE', *, *, #128, .F. ) ;
#201 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#202 = ORIENTED_EDGE ( 'NONE', *, *, #15, .F. ) ;
#203 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 0.000000000000000000, -500.0000000000000000 ) ) ;
#204 = DIRECTION ( 'NONE', ( -1.000000000000000000, -0.000000000000000000, -0.000000000000000000 ) ) ;
#205 = DIRECTION ( 'NONE', ( 1.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#206 = DIRECTION ( 'NONE', ( 0.000000000000000000, -0.000000000000000000, 1.000000000000000000 ) ) ;
#207 = DIRECTION ( 'NONE', ( -1.000000000000000000, 0.000000000000000000, -0.000000000000000000 ) ) ;
#208 = COORDINATED_UNIVERSAL_TIME_OFFSET ( 5, 0, .BEHIND. ) ;
#209 = DIRECTION ( 'NONE', ( 1.000000000000000000, 0.000000000000000000, 0.000000000000000000 ) ) ;
#210 = APPROVAL ( #190, 'UNSPECIFIED' ) ;
#211 = EDGE_CURVE ( 'NONE', #135, #74, #213, .T. ) ;
#212 = ORIENTED_EDGE ( 'NONE', *, *, #189, .T. ) ;
#213 = LINE ( 'NONE', #201, #33 ) ;
#214 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, -500.0000000000000000 ) ) ;
#215 = VERTEX_POINT ( 'NONE', #29 ) ;
#216 = DIRECTION ( 'NONE', ( -0.000000000000000000, -1.000000000000000000, -0.000000000000000000 ) ) ;
#217 = DIRECTION ( 'NONE', ( 0.000000000000000000, 0.000000000000000000, -1.000000000000000000 ) ) ;
#218 = CC_DESIGN_DATE_AND_TIME_ASSIGNMENT ( #52, #149, ( #180 ) ) ;
#219 = ADVANCED_FACE ( 'NONE', ( #181 ), #11, .F. ) ;
#220 = AXIS2_PLACEMENT_3D ( 'NONE', #79, #161, #206 ) ;
#221 = COORDINATED_UNIVERSAL_TIME_OFFSET ( 5, 0, .BEHIND. ) ;
#222 = ADVANCED_BREP_SHAPE_REPRESENTATION ( 'Cube_1m', ( #235, #1 ), #21 ) ;
#223 = SECURITY_CLASSIFICATION_LEVEL ( 'unclassified' ) ;
#224 = LOCAL_TIME ( 11, 10, 19.00000000000000000, #89 ) ;
#225 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT ( #20, #191, ( #51 ) ) ;
#226 = ADVANCED_FACE ( 'NONE', ( #22 ), #56, .F. ) ;
#227 = EDGE_LOOP ( 'NONE', ( #160, #200, #62, #182 ) ) ;
#228 = ORGANIZATION ( 'UNSPECIFIED', 'UNSPECIFIED', '' ) ;
#229 = DIRECTION ( 'NONE', ( -0.000000000000000000, -0.000000000000000000, -1.000000000000000000 ) ) ;
#230 = ORIENTED_EDGE ( 'NONE', *, *, #75, .F. ) ;
#231 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 1000.000000000000000, 500.0000000000000000 ) ) ;
#232 = CARTESIAN_POINT ( 'NONE', ( -500.0000000000000000, 0.000000000000000000, -500.0000000000000000 ) ) ;
#233 = DIRECTION ( 'NONE', ( -0.000000000000000000, -0.000000000000000000, -1.000000000000000000 ) ) ;
#234 = ADVANCED_FACE ( 'NONE', ( #3 ), #19, .F. ) ;
#235 = MANIFOLD_SOLID_BREP ( 'Boss-Extrude1', #67 ) ;
#236 = VECTOR ( 'NONE', #122, 1000.000000000000000 ) ;
#237 = APPROVAL_DATE_TIME ( #34, #95 ) ;
ENDSEC;
END-ISO-10303-21;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

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

View File

@ -2057,3 +2057,58 @@ const bracket = startSketchOn('XY')
r#"engine: KclErrorDetails { source_ranges: [SourceRange([1443, 1443])], message: "Modeling command failed: Some([ApiError { error_code: BadRequest, message: \"Fillet failed\" }])" }"# r#"engine: KclErrorDetails { source_ranges: [SourceRange([1443, 1443])], message: "Modeling command failed: Some([ApiError { error_code: BadRequest, message: \"Fillet failed\" }])" }"#
); );
} }
#[tokio::test(flavor = "multi_thread")]
async fn serial_test_error_empty_start_sketch_on_string() {
let code = r#"const part001 = startSketchOn('-XZ')
|> startProfileAt([75.75, 184.25], %)
|> line([190.03, -118.13], %)
|> line([-33.38, -202.86], %)
|> line([-315.86, -64.2], %)
|> tangentialArcTo([-147.66, 121.34], %)
|> close(%)
|> extrude(100, %)
const secondSketch = startSketchOn(part001, '')
|> circle([-20, 50], 40, %)
|> extrude(20, %)
"#;
let result = execute_and_snapshot(code, kcl_lib::settings::types::UnitLength::Mm).await;
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"type: KclErrorDetails { source_ranges: [SourceRange([272, 298])], message: "Expected a non-empty tag for the face to sketch on" }"#
);
}
#[tokio::test(flavor = "multi_thread")]
async fn serial_test_error_user_function_wrong_args() {
let code = r#"const length = .750
const width = 0.500
const height = 0.500
const dia = 4
fn squareHole = (l, w) => {
const squareHoleSketch = startSketchOn('XY')
|> startProfileAt([-width / 2, -length / 2], %)
|> lineTo([width / 2, -length / 2], %)
|> lineTo([width / 2, length / 2], %)
|> lineTo([-width / 2, length / 2], %)
|> close(%)
return squareHoleSketch
}
const extrusion = startSketchOn('XY')
|> circle([0, 0], dia/2, %)
|> hole(squareHole(length, width, height), %)
|> extrude(height, %)
"#;
let result = execute_and_snapshot(code, kcl_lib::settings::types::UnitLength::Mm).await;
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([92, 364]), SourceRange([444, 477])], message: "Expected 2 arguments, got 3" }"#
);
}

Some files were not shown because too many files have changed in this diff Show More