Compare commits

..

46 Commits

Author SHA1 Message Date
b4fb903bd0 Add recursive isEven() test 2024-07-22 20:03:49 -04:00
1b8688f274 Add lexical scope and redefining variables in functions (#3015)
* Fix to allow variable shadowing inside functions

* Implement closures

* Fix KCL test code to not reference future tag definition

* Remove tag declarator from function parameters

This is an example where the scoping change revealed a subtle issue
with TagDeclarators.  You cannot bind a new tag using a function
parameter.

The issue is that evaluating a TagDeclarator like $foo binds an
identifier to its corresponding TagIdentifier, but returns the
TagDeclarator.  If you have a TagDeclarator passed in as a parameter
to a function, you can never get its corresponding TagIdentifier.

This seems like a case where TagDeclarator evaluation needs to be
revisited, especially now that we have scoped tags.

* Fix to query return, functions, and tag declarator AST nodes correctly
2024-07-22 19:43:40 -04:00
397839da84 Fix syntax highlighting on code pane open/close (#3083) 2024-07-20 01:45:38 -07:00
ac120838e5 setIsLoading false earlier (#3072)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-19 22:18:31 -04:00
e6a2ac9c4a Typecheck KCL args via generics, not handwritten impls (#3025)
In KCL, arguments to functions are passed in the Args struct. This struct contains a list of args, but each arg could be any KCL type (they're stored in an enum of all possible types). To get args of the correct type, these enums are fallibly converted into the type expected for the matching parameter.

Until now, the fallible conversion was handwritten for nearly each function. This is unnecessary, I've replaced it with composable traits.
2024-07-19 20:30:13 -05:00
6e7e6e96cf Make engine reconnection test pass every time (#3066)
* Ensure that isFreezeFrame is reset by isFirstRender, because it can't be a freeze frame if it's the first render

* `restart`-type engine starts should count as first renders

* Ensure we don't see a loading spinner after network is reconnected in test

* Make `waitForPageLoad` robust against if the page has already loaded
and make it actually wait for the Start Sketch button to be enabled

---------

Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-07-18 16:16:17 -04:00
73e155d79b Fix JS error about fill-rule when opening user menu (#3069) 2024-07-18 20:13:40 +00:00
a782f26ec2 Use ..Default::default() with a struct constructor (#3068)
As @jtran pointed out - I had misunderstood the behavior of
Default::default(), we can instead rely on this syntax to do the same
thing. This won't use each field's default value -- rather, it'll use
the type's Default, and override each field. Neat!

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>
2024-07-18 15:20:50 -04:00
01076c3aed Remove sidebar menus in favor of lil' popovers (#3046)
* Convert user menu to a popover from a sidebar

* Move the user menu over to the left menu cluster

* Replace project sidebar with popover-style menu

* Styling tweaks, give export button a proper tooltip when disabled

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

* Filter orphan breaks, tweak space to remove mouse gaps

* Unify with and without avatar image code

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

* Rerun CI

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

* Rerun CI

* Prepare to move UserSidebarMenu over to right

* Revert AppHeader tweaks

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

* Rerun CI

* Fix typo in README

* Fix export E2E tests that relied on button text

* Missed the data-testid we used to have on the data-testid we had on the settings button

* Dang I missed another testId

* Update snapshots

* 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-07-18 14:29:15 -04:00
fe512611ac Fix doc comment to match generated docs (#3067) 2024-07-18 18:00:06 +00:00
cba953c245 Cut release v0.24.3 (#3053) 2024-07-18 10:55:23 -07:00
54ca6ea0b2 artifact map clean up 1 (#3064)
remove old shit
2024-07-18 17:52:39 +10:00
max
6a01608c3a Unit Tests for hasValidFilletSelection (#3063)
* tests

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

* "err" instead of "instanceof Error"

* trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
2024-07-18 16:33:49 +10:00
530f15e04a switch to js 2024-07-17 19:49:50 -04:00
725e59d987 use shell for now 2024-07-17 19:47:02 -04:00
54313c9b03 fix template again 2024-07-17 19:44:02 -04:00
890d96496c add a new cryptic_error template 2024-07-17 19:42:28 -04:00
35999366a7 Stl test for larger file (#3052)
* add shit

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

* add image

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

* images updated

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-17 15:55:59 -07:00
2affc7271d Bump max_frame_size (#3050)
We use the WebSocket connection to send binary data (in the form of
shapefiles) from the engine to the client. These can very easily get
larger than the default 16MB limit on the max_frame_size. I don't
understand why it won't stich multiple frames together - but given what
I can see when this crashes, the max_message_size isn't the LIMFAC,
max_frame_size is.

That's an issue for future-us.

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>
2024-07-17 15:32:57 -04:00
d30fbf8b4b Bump tokio from 1.38.0 to 1.38.1 in /src/wasm-lib (#3043)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.38.0 to 1.38.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.38.0...tokio-1.38.1)

---
updated-dependencies:
- dependency-name: tokio
  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-07-17 09:06:39 -07:00
3f7e776464 Improve 'Release a new version' readme (#3048) 2024-07-17 10:23:21 -04:00
79cff57f43 show default planes bug (#3047) 2024-07-17 18:58:01 +10:00
1cd2cd82b2 Add a close button to sidebar panes (#3038)
* Add a close button to sidebar panes

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

* Rerun CI

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

* Fix up dark mode look and feel

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-17 01:17:53 -04:00
60e187bd3e Fix defined but never used warnings (#3045) 2024-07-17 04:26:14 +00:00
c64175425b Updater smoke-test instructions (#3044)
updater smoke test instructions
2024-07-17 14:00:05 +10:00
36464e6984 fillet ui follow up (#3035) 2024-07-17 03:58:48 +00:00
2f0002e53c Cut release v0.24.2 (#3042) 2024-07-17 13:55:17 +10:00
482833c88f Lf94/pause improvements (#3032)
* Add stream idle mode as a setting (default is off)

* Add pause icon
2024-07-17 12:45:11 +10:00
d9d0a72306 Remove unused function ProgramMemory::get_tags (#3033)
Seems to be unused since #2941.
2024-07-16 15:12:05 -04:00
65cd9fab64 Revert the snapshots. (#3039)
* Revert "Compute the AST digest in the LSP (#3037)"

This reverts commit 5e41e382ce.

* Compute the AST digest in the LSP (#3037)

This is a slow-roll to calling this in more places; but this is
non-critical, so if this breaks on some unexpected AST or what have you,
we're not breaking anything except the LSP (which we'll see pretty
quickly) while also testing it on all user input.

If something goes south, please feel free to revert this commit.

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>

---------

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>
2024-07-16 13:16:51 -04:00
5e41e382ce Compute the AST digest in the LSP (#3037)
This is a slow-roll to calling this in more places; but this is
non-critical, so if this breaks on some unexpected AST or what have you,
we're not breaking anything except the LSP (which we'll see pretty
quickly) while also testing it on all user input.

If something goes south, please feel free to revert this commit.

Signed-off-by: Paul Tagliamonte <paul@zoo.dev>
2024-07-16 12:13:17 -04:00
1e3cb00092 Move Args into its own module (#3027) 2024-07-16 07:45:43 -05:00
d1a2bd01ca Lower threshold for 2020 tests (#3030)
* Lower threshold for 2020 tests

Now that the tests zoom into the model and center it before taking a
snapshot, they should be less sensitive.

* Genuine, nontrivial changes to the integration test images
2024-07-15 17:41:41 -05:00
aca13d087b add in benchmarks for digest code (#3031)
(initial results look good!)
2024-07-15 13:45:55 -04:00
fcdde3e482 Bump syn from 2.0.70 to 2.0.71 in /src/wasm-lib (#3029)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.70 to 2.0.71.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.70...2.0.71)

---
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-07-15 09:26:18 -07:00
a1df3d0ffc Fillet UI (#2718)
* draft: fillet ast mod + test

* Kurt's rejig

* playwright

* update button enable logic

* remove fillet button in production build

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

* trigger CI

* fix typo

* give a way to turn on fillets

---------

Co-authored-by: max-mrgrsk <margorskyi@gmail.com>
Co-authored-by: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-15 19:20:32 +10:00
1852e6167b Fix argument persistence and accidental submission command bar bugs (#3021) 2024-07-14 18:15:34 -04:00
29bf77bb82 Show descriptions for generated commands, make them look better and sort better (#3023) 2024-07-12 17:48:38 -04:00
e81b614523 Lf94/save settings between reconnects (#2997)
* Keep settings between reconnects

* Set idle timeout to 2 minutes

* Put idle behind flags

* Remove pauses

* Fix online->offline->online

* Revert "Remove pauses"

This reverts commit 267ef4ff4b86f2d8014bfb2a8e8a633adc8001dc.

* ci

* call correct setmediastream
2024-07-12 20:42:23 +00:00
5a5fe3bb95 Add sketch tools back to the command bar (#3008)
* Make machine command type names more explicit

* Prepare "change tool" event for command bar

* Make it so that state machine events can each map to multiple command configs

* Make commands with all skippable args possible

* Add back the tools to the command bar

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

* Update to use new `groupId` property name

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

* Oops didn't save this other instance of `ownerMachine`

* Add a playwright test

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-12 16:16:26 -04:00
0710f6e5f2 Add format code to the command palette (#3001)
* Add format code to the command palette

* Fix to use renamed groupId parameter

* Add icon to format code command

* Fix to remove commands during teardown

* Fix dependencies

* Change formatting
2024-07-12 17:08:01 +00:00
c9d5633647 Bump thiserror from 1.0.61 to 1.0.62 in /src/wasm-lib (#3016)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.61 to 1.0.62.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.61...1.0.62)

---
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-07-12 09:11:49 -07:00
f9419a98b5 Cut release v0.24.1 (#3014) 2024-07-11 21:51:58 -04:00
999f72bccf mediaStream (#3013)
* mediaStream

* make vitest happy

* fmt
2024-07-11 20:57:27 -04:00
9dbe74e008 cleaner hack (#3012) 2024-07-12 09:41:39 +10:00
88d9cdc52b Codemirror deferrers (#3006)
* Force document update requests when necessary

* fix up codemirror deferrers

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

* lock

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

* fixups kcl/index

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

* fix copilot

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>

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Marijn Haverbeke <marijn@haverbeke.berlin>
2024-07-11 16:05:19 -07:00
361 changed files with 164720 additions and 2504 deletions

View File

@ -0,0 +1,37 @@
name: Cryptic KCL Error
description: File a bug report for source code that produces a confusing error
title: "[CRYPTIC]: "
labels: ["cryptic-error"]
assignees: []
body:
- type: markdown
attributes:
value: "Thank you for taking the time to report a confusing error. Please provide as much information as possible to help us resolve it."
- type: textarea
id: kcl
attributes:
label: Paste minimal KCL source that produces a cryptic error
description: Minimal KCL reproducer that produces a cryptic error
placeholder: "const ..."
render: javascript
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: Description of what you expected to happen (if you know).
placeholder: "I expected that..."
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context about the problem here.
placeholder: "Anything else you want to add..."
validations:
required: false

View File

@ -124,20 +124,40 @@ Before you submit a contribution PR to this repo, please ensure that:
## Release a new version
1. Bump the versions by running `./make-realease.sh` while on a fresh pull of main
#### 1. Bump the versions by running `./make-release.sh` and create a Cut Release PR
That will create the branch with the updated json files for you.
run `./make-release.sh` for a patch update
run `./make-release.sh "minor"` for minor
run `./make-release.sh "major"` for major
That will create the branch with the updated json files for you:
- run `./make-release.sh` or `./make-release.sh patch` for a patch update;
- run `./make-release.sh minor` for minor; or
- run `./make-release.sh major` for major.
After it runs you should just need to push the push the branch and open a PR (it will suggest a changelog for you too, delete any that are not user facing)
After it runs you should just need the push the branch and open a PR.
The PR may serve as a place to discuss the human-readable changelog and extra QA.
**Important:** It needs to be prefixed with `Cut release v` to build in release mode and a few other things to test in the best context possible, the intent would be for instance to have `Cut release v1.2.3` for the `v1.2.3` release candidate.
2. Merge the PR
The PR may then serve as a place to discuss the human-readable changelog and extra QA. The `make-release.sh` tool suggests a changelog for you too to be used as PR description, just make sure to delete lines that are not user facing.
#### 2. Smoke test artifacts from the Cut Release PR
The release builds can be find under the `artifact` zip, at the very bottom of the `ci` action page for each commit on this branch.
We don't have a strict process, but click around and check for anything obvious, posting results as comments in the Cut Release PR.
The other `ci` output in Cut Release PRs is `updater-test`, because we don't have a way to test this fully automated, we have a semi-automated process. Download updater-test zip file, install the app, run it, expect an updater prompt to a dummy v0.99.99, install it and check that the app comes back at that version (on both macOS and Windows).
#### 3. Merge the Cut Release PR
This will kick the `create-release` action, that creates a _Draft_ release out of this Cut Release PR merge after less than a minute, with the new version as title and Cut Release PR as description.
#### 4. Publish the release
Head over to https://github.com/KittyCAD/modeling-app/releases, the draft release corresponding to the merged Cut Release PR should show up at the top as _Draft_. Click on it, verify the content, and hit _Publish_.
#### 5. Profit
A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions, which can be found under `release` event filter.
3. Profit (A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions if the PR was correctly named)
## Fuzzing the parser

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -3099,6 +3099,49 @@ const sketch002 = startSketchOn(extrude001, $seg01)
).not.toBeDisabled()
})
test('Fillet button states test', async ({ page }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)`
)
})
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
const selectSegment = () => page.getByText(`line([10, 0], %)`).click()
const selectClose = () => page.getByText(`close(%)`).click()
const clickEmpty = () => page.mouse.click(950, 100)
// expect fillet button without any bodies in the scene
await selectSegment()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
await clickEmpty()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
// test fillet button with the body in the scene
const codeToAdd = `${await u.codeLocator.allInnerTexts()}
const extrude001 = extrude(10, sketch001)`
await u.codeLocator.fill(codeToAdd)
await selectSegment()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
await selectClose()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
await clickEmpty()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
})
const removeAfterFirstParenthesis = (inputString: string) => {
const index = inputString.indexOf('(')
if (index !== -1) {
@ -3500,11 +3543,62 @@ test.describe('Command bar tests', () => {
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
)
})
test('Command bar works and can change a setting', async ({ page }) => {
test('Fillet from command bar', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XY')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
const extrude001 = extrude(-10, sketch001)`
)
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
const selectSegment = () => page.getByText(`line([0, -10], %)`).click()
await selectSegment()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Fillet' }).click()
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await expect(page.locator('.cm-activeLine')).toContainText(
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
)
})
test('Command bar can change a setting, and switch back and forth between arguments', async ({
page,
}) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
const commandBarButton = page.getByRole('button', { name: 'Commands' })
const cmdSearchBar = page.getByPlaceholder('Search commands')
const themeOption = page.getByRole('option', {
name: 'theme',
exact: false,
})
const commandLevelArgButton = page.getByRole('button', { name: 'level' })
const commandThemeArgButton = page.getByRole('button', { name: 'value' })
// This selector changes after we set the setting
let commandOptionInput = page.getByPlaceholder('Select an option')
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
@ -3515,23 +3609,17 @@ test.describe('Command bar tests', () => {
.or(page.getByRole('button', { name: '⌘K' }))
.click()
let cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).toBeVisible()
await page.keyboard.press('Escape')
cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).not.toBeVisible()
// Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('Meta+K')
cmdSearchBar = page.getByPlaceholder('Search commands')
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 cmdSearchBar.fill('theme')
await expect(themeOption).toBeVisible()
await themeOption.click()
const themeInput = page.getByPlaceholder('Select an option')
@ -3553,6 +3641,24 @@ test.describe('Command bar tests', () => {
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
commandOptionInput = page.getByPlaceholder('system')
// Test case for https://github.com/KittyCAD/modeling-app/issues/2882
await commandBarButton.click()
await cmdSearchBar.focus()
await cmdSearchBar.fill('theme')
await themeOption.click()
await expect(commandThemeArgButton).toBeDisabled()
await commandOptionInput.focus()
await commandOptionInput.fill('lig')
await commandLevelArgButton.click()
await expect(commandLevelArgButton).toBeDisabled()
// Test case for https://github.com/KittyCAD/modeling-app/issues/2881
await commandThemeArgButton.click()
await expect(commandThemeArgButton).toBeDisabled()
await expect(commandLevelArgButton).toHaveText('level: project')
})
test('Command bar keybinding works from code editor and can change a setting', async ({
@ -3577,7 +3683,7 @@ test.describe('Command bar tests', () => {
await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar
await page.keyboard.type('theme')
await cmdSearchBar.fill('theme')
const themeOption = page.getByRole('option', {
name: 'Settings · app · theme',
})
@ -3648,7 +3754,9 @@ test.describe('Command bar tests', () => {
await page.mouse.click(700, 200)
// Assert that we're on the distance step
await expect(page.getByRole('button', { name: 'distance' })).toBeDisabled()
await expect(
page.getByRole('button', { name: 'distance', exact: false })
).toBeDisabled()
// Assert that the an alternative variable name is chosen,
// since the default variable name is already in use (distance)
@ -3663,11 +3771,12 @@ test.describe('Command bar tests', () => {
// Review step and argument hotkeys
await expect(submitButton).toBeEnabled()
await page.keyboard.press('Backspace')
await expect(submitButton).toBeFocused()
await submitButton.press('Backspace')
// Assert we're back on the distance step
await expect(
page.getByRole('button', { name: 'Distance 5', exact: false })
page.getByRole('button', { name: 'distance', exact: false })
).toBeDisabled()
await continueButton.click()
@ -3691,6 +3800,47 @@ const extrude001 = extrude(distance001, sketch001)`.replace(
) // remove newlines
)
})
test('Can switch between sketch tools via command bar', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
const cmdBarButton = page.getByRole('button', { name: 'Commands' })
const rectangleToolCommand = page.getByRole('option', {
name: 'Rectangle',
})
const rectangleToolButton = page.getByRole('button', { name: 'Rectangle' })
const lineToolCommand = page.getByRole('option', { name: 'Line' })
const lineToolButton = page.getByRole('button', { name: 'Line' })
const arcToolCommand = page.getByRole('option', { name: 'Tangential Arc' })
const arcToolButton = page.getByRole('button', { name: 'Tangential Arc' })
// Start a sketch
await sketchButton.click()
await page.mouse.click(700, 200)
// Switch between sketch tools via the command bar
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
await cmdBarButton.click()
await rectangleToolCommand.click()
await expect(rectangleToolButton).toHaveAttribute('aria-pressed', 'true')
await cmdBarButton.click()
await lineToolCommand.click()
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
// Click in the scene a couple times to draw a line
// so tangential arc is valid
await page.mouse.click(700, 200)
await page.mouse.move(700, 300, { steps: 5 })
await page.mouse.click(700, 300)
// switch to tangential arc via command bar
await cmdBarButton.click()
await arcToolCommand.click()
await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
})
})
test.describe('Regression tests', () => {
@ -4642,10 +4792,10 @@ test.describe('Sketch tests', () => {
// click extrude
await page.getByRole('button', { name: 'Extrude' }).click()
// sketch selection should already have been made. "Selection 1 face" only show up when the selection has been made already
// sketch selection should already have been made. "Selection: 1 face" only show up when the selection has been made already
// otherwise the cmdbar would be waiting for a selection.
await expect(
page.getByRole('button', { name: 'Selection 1 face' })
page.getByRole('button', { name: 'selection : 1 face', exact: false })
).toBeVisible()
})
test("Existing sketch with bad code delete user's code", async ({ page }) => {
@ -7071,6 +7221,7 @@ test.describe('Test network and connection issues', () => {
// Expect the network to be up
await expect(page.getByText('Network Health (Connected)')).toBeVisible()
await expect(page.getByTestId('loading-stream')).not.toBeAttached()
// Click off the code pane.
await page.mouse.click(100, 100)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 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: 71 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -16,14 +16,14 @@ export const TEST_COLORS = {
} as const
async function waitForPageLoad(page: Page) {
// wait for 'Loading stream...' spinner
await page.getByTestId('loading-stream').waitFor()
// wait for all spinners to be gone
await page
.getByTestId('loading')
.waitFor({ state: 'detached', timeout: 20_000 })
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await page.getByTestId('start-sketch').waitFor()
await expect(page.getByTestId('start-sketch')).toBeEnabled({
timeout: 20_000,
})
}
async function removeCurrentCode(page: Page) {
@ -471,8 +471,10 @@ export const doExport = async (
page: Page
): Promise<Paths> => {
await page.getByRole('button', { name: APP_NAME }).click()
await expect(page.getByRole('button', { name: 'Export Part' })).toBeVisible()
await page.getByRole('button', { name: 'Export Part' }).click()
await expect(
page.getByRole('button', { name: 'Export', exact: false })
).toBeVisible()
await page.getByRole('button', { name: 'Export', exact: false }).click()
await expect(page.getByTestId('command-bar')).toBeVisible()
// Go through export via command bar

View File

@ -77,7 +77,7 @@ describe('ZMA authorized user flows', () => {
const menuButton = await $('[data-testid="user-sidebar-toggle"]')
await click(menuButton)
const settingsButton = await $('[data-testid="settings-button"]')
const settingsButton = await $('[data-testid="user-settings"]')
await click(settingsButton)
const projectDirInput = await $('[data-testid="project-directory-input"]')

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.24.0",
"version": "0.24.3",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.17.0",

View File

@ -30,7 +30,7 @@ import { URI } from 'vscode-uri'
import { LanguageServerClient } from '../client'
import { CompletionItemKindMap } from './autocomplete'
import { addToken, SemanticToken } from './semantic-tokens'
import { deferExecution, posToOffset, formatMarkdownContents } from './util'
import { posToOffset, formatMarkdownContents } from './util'
import lspAutocompleteExt from './autocomplete'
import lspHoverExt from './hover'
import lspFormatExt from './format'
@ -93,23 +93,10 @@ export class LanguageServerPlugin implements PluginValue {
private doSemanticTokens: boolean = false
private doFoldingRanges: boolean = false
private _defferer = deferExecution((code: string) => {
try {
// Update the state (not the editor) with the new code.
this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: code }],
})
this.requestSemanticTokens()
this.updateFoldingRanges()
} catch (e) {
console.error(e)
}
}, this.changesDelay)
// When a doc update needs to be sent to the server, this holds the
// timeout handle for it. When null, the server has the up-to-date
// document.
private sendScheduled: number | null = null
constructor(options: LanguageServerOptions, private view: EditorView) {
this.client = options.client
@ -152,14 +139,9 @@ export class LanguageServerPlugin implements PluginValue {
}
update(viewUpdate: ViewUpdate) {
// If the doc didn't change we can return early.
if (!viewUpdate.docChanged) {
return
if (viewUpdate.docChanged) {
this.scheduleSendDoc()
}
this.sendChange({
documentText: viewUpdate.state.doc.toString(),
})
}
destroy() {
@ -184,16 +166,6 @@ export class LanguageServerPlugin implements PluginValue {
this.updateFoldingRanges()
}
async sendChange({ documentText }: { documentText: string }) {
if (!this.client.ready) return
this._defferer(documentText)
}
requestDiagnostics() {
this.sendChange({ documentText: this.getDocText() })
}
async requestHoverTooltip(
view: EditorView,
{ line, character }: { line: number; character: number }
@ -204,7 +176,7 @@ export class LanguageServerPlugin implements PluginValue {
)
return null
this.sendChange({ documentText: this.getDocText() })
this.ensureDocSent()
const result = await this.client.textDocumentHover({
textDocument: { uri: this.getDocUri() },
position: { line, character },
@ -227,6 +199,42 @@ export class LanguageServerPlugin implements PluginValue {
return { pos, end, create: (view) => ({ dom }), above: true }
}
scheduleSendDoc() {
if (this.sendScheduled != null) window.clearTimeout(this.sendScheduled)
this.sendScheduled = window.setTimeout(
() => this.sendDoc(),
this.changesDelay
)
}
sendDoc() {
if (this.sendScheduled != null) {
window.clearTimeout(this.sendScheduled)
this.sendScheduled = null
}
if (!this.client.ready) return
try {
// Update the state (not the editor) with the new code.
this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: this.view.state.doc.toString() }],
})
this.requestSemanticTokens()
this.updateFoldingRanges()
} catch (e) {
console.error(e)
}
}
ensureDocSent() {
if (this.sendScheduled != null) this.sendDoc()
}
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
if (
!this.doFoldingRanges ||
@ -284,13 +292,7 @@ export class LanguageServerPlugin implements PluginValue {
)
return null
this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: this.getDocText() }],
})
this.ensureDocSent()
const result = await this.client.textDocumentFormatting({
textDocument: { uri: this.getDocUri() },
@ -330,9 +332,7 @@ export class LanguageServerPlugin implements PluginValue {
)
return null
this.sendChange({
documentText: context.state.doc.toString(),
})
this.ensureDocSent()
const result = await this.client.textDocumentCompletion({
textDocument: { uri: this.getDocUri() },

108
src-tauri/Cargo.lock generated
View File

@ -332,7 +332,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -367,7 +367,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -407,7 +407,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -550,7 +550,7 @@ dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
"syn_derive",
]
@ -823,7 +823,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1073,7 +1073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1083,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1107,7 +1107,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.10.0",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1118,7 +1118,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [
"darling_core",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1179,7 +1179,7 @@ checksum = "4078275de501a61ceb9e759d37bdd3d7210e654dbc167ac1a3678ef4435ed57b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
"synstructure",
]
@ -1216,7 +1216,7 @@ dependencies = [
"regex",
"serde",
"serde_tokenstream",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1227,7 +1227,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1288,7 +1288,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1320,7 +1320,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1427,7 +1427,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1588,7 +1588,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1704,7 +1704,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -1980,7 +1980,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -2008,7 +2008,7 @@ dependencies = [
"inflections",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -2083,7 +2083,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -3377,7 +3377,7 @@ dependencies = [
"regex",
"regex-syntax 0.8.3",
"structmeta",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -3496,7 +3496,7 @@ dependencies = [
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -3564,7 +3564,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4438,7 +4438,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4558,7 +4558,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4569,7 +4569,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4602,7 +4602,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4623,7 +4623,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4665,7 +4665,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4933,7 +4933,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4944,7 +4944,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4966,7 +4966,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -4999,9 +4999,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.70"
version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [
"proc-macro2",
"quote",
@ -5017,7 +5017,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -5034,7 +5034,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -5251,7 +5251,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
"syn 2.0.70",
"syn 2.0.71",
"tauri-utils",
"thiserror",
"time",
@ -5269,7 +5269,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
"tauri-codegen",
"tauri-utils",
]
@ -5627,22 +5627,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]]
name = "thiserror"
version = "1.0.61"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.61"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -5740,7 +5740,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -5940,7 +5940,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -5969,7 +5969,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -6099,7 +6099,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
"termcolor",
]
@ -6316,7 +6316,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -6415,7 +6415,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
"wasm-bindgen-shared",
]
@ -6449,7 +6449,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -6590,7 +6590,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -6696,7 +6696,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -6707,7 +6707,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]
@ -7159,7 +7159,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.70",
"syn 2.0.71",
]
[[package]]

View File

@ -80,5 +80,5 @@
}
},
"productName": "Zoo Modeling App",
"version": "0.24.0"
"version": "0.24.3"
}

View File

@ -26,7 +26,6 @@ import useHotkeyWrapper from 'lib/hotkeyWrapper'
import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump'
import { UnitsMenu } from 'components/UnitsMenu'
import { useAppState } from 'AppState'
export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS')
@ -45,9 +44,7 @@ export function App() {
}, [projectName, projectPath])
useHotKeyListener()
const { context } = useModelingContext()
const { streamDimensions, didDragInStream, buttonDownInStream } =
useAppState()
const { context, state } = useModelingContext()
const { auth, settings } = useSettingsAuthContext()
const token = auth?.context?.token
@ -60,7 +57,6 @@ export function App() {
const {
app: { onboardingStatus },
} = settings.context
const { state } = useModelingContext()
useHotkeys('backspace', (e) => {
e.preventDefault()
@ -77,7 +73,7 @@ export function App() {
(p) => p === onboardingStatus.current
)
? 'opacity-20'
: didDragInStream
: context.store?.didDragInStream
? 'opacity-40'
: ''
@ -95,11 +91,11 @@ export function App() {
clientX: e.clientX,
clientY: e.clientY,
el: e.currentTarget,
...streamDimensions,
...context.store?.streamDimensions,
})
const newCmdId = uuidv4()
if (buttonDownInStream === undefined) {
if (context.store?.buttonDownInStream === undefined) {
debounceSocketSend({
type: 'modeling_cmd_req',
cmd: {
@ -121,7 +117,7 @@ export function App() {
className={
'transition-opacity transition-duration-75 ' +
paneOpacity +
(buttonDownInStream ? ' pointer-events-none' : '')
(context.store?.buttonDownInStream ? ' pointer-events-none' : '')
}
project={{ project, file }}
enableMenu={true}

View File

@ -1,10 +1,4 @@
import {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from 'react'
import { createContext, useContext, useState, ReactNode } from 'react'
/*
@ -17,23 +11,11 @@ Please do not fill this up with junk.
interface AppState {
isStreamReady: boolean
setAppState: (newAppState: Partial<AppState>) => void
mediaStream?: MediaStream
buttonDownInStream: number | undefined
didDragInStream: boolean
streamDimensions: { streamWidth: number; streamHeight: number }
// openPanes: SidebarType[]
}
const AppStateContext = createContext<AppState>({
isStreamReady: false,
setAppState: () => {},
buttonDownInStream: undefined,
didDragInStream: false,
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
mediaStream: undefined,
// openPanes: persistedContext.openPanes || ['code'],
})
export const useAppState = () => useContext(AppStateContext)
@ -42,38 +24,47 @@ export const AppStateProvider = ({ children }: { children: ReactNode }) => {
const [appState, _setAppState] = useState<AppState>({
isStreamReady: false,
setAppState: () => {},
buttonDownInStream: undefined,
didDragInStream: false,
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
mediaStream: undefined,
// openPanes: persistedContext.openPanes || ['code'],
})
useEffect(() => {
// console.log('appState change', appState)
}, [appState])
const setAppState = (newAppState: Partial<AppState>) => {
// console.log('appstate', newAppState)
_setAppState({
...appState,
...newAppState,
mediaStream: newAppState.mediaStream || appState.mediaStream,
})
}
const setAppState = (newAppState: Partial<AppState>) =>
_setAppState({ ...appState, ...newAppState })
return (
<AppStateContext.Provider
value={{
isStreamReady: appState.isStreamReady,
setAppState,
mediaStream: appState.mediaStream,
buttonDownInStream: appState.buttonDownInStream,
didDragInStream: appState.didDragInStream,
streamDimensions: appState.streamDimensions,
}}
>
{children}
</AppStateContext.Provider>
)
}
interface AppStream {
mediaStream: MediaStream
setMediaStream: (mediaStream: MediaStream) => void
}
const AppStreamContext = createContext<AppStream>({
mediaStream: undefined as unknown as MediaStream,
setMediaStream: () => {},
})
export const useAppStream = () => useContext(AppStreamContext)
export const AppStreamProvider = ({ children }: { children: ReactNode }) => {
const [mediaStream, setMediaStream] = useState<MediaStream>(
undefined as unknown as MediaStream
)
return (
<AppStreamContext.Provider
value={{
mediaStream,
setMediaStream,
}}
>
{children}
</AppStreamContext.Provider>
)
}

View File

@ -49,17 +49,17 @@ const router = createBrowserRouter([
/* Make sure auth is the outermost provider or else we will have
* inefficient re-renders, use the react profiler to see. */
element: (
<AppStateProvider>
<CommandBarProvider>
<SettingsAuthProvider>
<LspProvider>
<KclContextProvider>
<CommandBarProvider>
<SettingsAuthProvider>
<LspProvider>
<KclContextProvider>
<AppStateProvider>
<Outlet />
</KclContextProvider>
</LspProvider>
</SettingsAuthProvider>
</CommandBarProvider>
</AppStateProvider>
</AppStateProvider>
</KclContextProvider>
</LspProvider>
</SettingsAuthProvider>
</CommandBarProvider>
),
errorElement: <ErrorPage />,
children: [

View File

@ -16,6 +16,7 @@ import {
canRectangleTool,
isEditingExistingSketch,
} from 'machines/modelingMachine'
import { DEV } from 'env'
export function Toolbar({
className = '',
@ -60,7 +61,7 @@ export function Toolbar({
? send('CancelSketch')
: send({
type: 'change tool',
data: 'line',
data: { tool: 'line' },
}),
{ enabled: !disableLineButton, scopes: ['sketch'] }
)
@ -75,7 +76,7 @@ export function Toolbar({
? send('CancelSketch')
: send({
type: 'change tool',
data: 'tangentialArc',
data: { tool: 'tangentialArc' },
}),
{ enabled: !disableTangentialArc, scopes: ['sketch'] }
)
@ -89,7 +90,7 @@ export function Toolbar({
? send('CancelSketch')
: send({
type: 'change tool',
data: 'rectangle',
data: { tool: 'rectangle' },
}),
{ enabled: !disableRectangle, scopes: ['sketch'] }
)
@ -118,6 +119,16 @@ export function Toolbar({
}),
{ enabled: !disableAllButtons, scopes: ['modeling'] }
)
const disableFillet = !state.can('Fillet') || disableAllButtons
useHotkeys(
'f',
() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', groupId: 'modeling' },
}),
{ enabled: !disableFillet, scopes: ['modeling'] }
)
function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
const span = toolbarButtonsRef.current
@ -263,7 +274,7 @@ export function Toolbar({
? send('CancelSketch')
: send({
type: 'change tool',
data: 'line',
data: { tool: 'line' },
})
}
aria-pressed={state?.matches('Sketch.Line tool')}
@ -293,7 +304,7 @@ export function Toolbar({
? send('CancelSketch')
: send({
type: 'change tool',
data: 'tangentialArc',
data: { tool: 'tangentialArc' },
})
}
aria-pressed={state.matches('Sketch.Tangential arc to')}
@ -323,7 +334,7 @@ export function Toolbar({
? send('CancelSketch')
: send({
type: 'change tool',
data: 'rectangle',
data: { tool: 'rectangle' },
})
}
aria-pressed={state.matches('Sketch.Rectangle tool')}
@ -404,6 +415,36 @@ export function Toolbar({
</ActionButton>
</li>
)}
{state.matches('idle') && (DEV || (window as any)._enableFillet) && (
<li className="contents">
<ActionButton
className={buttonClassName}
Element="button"
onClick={() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', groupId: 'modeling' },
})
}
disabled={disableFillet}
title={disableFillet ? 'fillet' : "edge can't be filleted"}
iconStart={{
icon: 'fillet', // todo: add fillet icon
iconClassName,
bgClassName,
}}
>
Fillet
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: F
</Tooltip>
</ActionButton>
</li>
)}
</ul>
</menu>
)

View File

@ -47,7 +47,6 @@ import {
PipeExpression,
Program,
ProgramMemory,
programMemoryInit,
recast,
SketchGroup,
ExtrudeGroup,
@ -130,7 +129,7 @@ export const HIDE_HOVER_SEGMENT_LENGTH = 60 // in pixels
export class SceneEntities {
engineCommandManager: EngineCommandManager
scene: Scene
sceneProgramMemory: ProgramMemory = { root: {}, return: null }
sceneProgramMemory: ProgramMemory = ProgramMemory.empty()
activeSegments: { [key: string]: Group } = {}
intersectionPlane: Mesh | null = null
axisGroup: Group | null = null
@ -550,9 +549,9 @@ export class SceneEntities {
const variableDeclarationName =
_node1.node?.declarations?.[0]?.id?.name || ''
const sg = kclManager.programMemory.root[
const sg = kclManager.programMemory.get(
variableDeclarationName
] as SketchGroup
) as SketchGroup
const lastSeg = sg.value.slice(-1)[0] || sg.start
const index = sg.value.length // because we've added a new segment that's not in the memory yet, no need for `-1`
@ -768,9 +767,9 @@ export class SceneEntities {
programMemoryOverride,
})
this.sceneProgramMemory = programMemory
const sketchGroup = programMemory.root[
const sketchGroup = programMemory.get(
variableDeclarationName
] as SketchGroup
) as SketchGroup
const sgPaths = sketchGroup.value
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
@ -820,9 +819,9 @@ export class SceneEntities {
// Prepare to update the THREEjs scene
this.sceneProgramMemory = programMemory
const sketchGroup = programMemory.root[
const sketchGroup = programMemory.get(
variableDeclarationName
] as SketchGroup
) as SketchGroup
const sgPaths = sketchGroup.value
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
@ -1081,9 +1080,9 @@ export class SceneEntities {
})
this.sceneProgramMemory = programMemory
const maybeSketchGroup = programMemory.root[variableDeclarationName]
const maybeSketchGroup = programMemory.get(variableDeclarationName)
let sketchGroup = undefined
if (maybeSketchGroup.type === 'SketchGroup') {
if (maybeSketchGroup?.type === 'SketchGroup') {
sketchGroup = maybeSketchGroup
} else if ((maybeSketchGroup as ExtrudeGroup).sketchGroup) {
sketchGroup = (maybeSketchGroup as ExtrudeGroup).sketchGroup
@ -1773,7 +1772,7 @@ function prepareTruncatedMemoryAndAst(
if (err(_node)) return _node
const variableDeclarationName = _node.node?.declarations?.[0]?.id?.name || ''
const lastSeg = (
programMemory.root[variableDeclarationName] as SketchGroup
programMemory.get(variableDeclarationName) as SketchGroup
).value.slice(-1)[0]
if (draftSegment) {
// truncatedAst needs to setup with another segment at the end
@ -1824,33 +1823,27 @@ function prepareTruncatedMemoryAndAst(
..._ast,
body: [JSON.parse(JSON.stringify(_ast.body[bodyIndex]))],
}
const programMemoryOverride = programMemoryInit()
if (err(programMemoryOverride)) return programMemoryOverride
// Grab all the TagDeclarators and TagIdentifiers from memory.
let start = _node.node.start
for (const key in programMemory.root) {
const value = programMemory.root[key]
if (!('__meta' in value)) {
continue
}
const programMemoryOverride = programMemory.filterVariables(true, (value) => {
if (
!('__meta' in value) ||
value.__meta === undefined ||
value.__meta.length === 0 ||
value.__meta[0].sourceRange === undefined
) {
continue
return false
}
if (value.__meta[0].sourceRange[0] >= start) {
// We only want things before our start point.
continue
return false
}
if (value.type === 'TagIdentifier') {
programMemoryOverride.root[key] = JSON.parse(JSON.stringify(value))
}
}
return value.type === 'TagIdentifier'
})
if (err(programMemoryOverride)) return programMemoryOverride
for (let i = 0; i < bodyIndex; i++) {
const node = _ast.body[i]
@ -1858,12 +1851,15 @@ function prepareTruncatedMemoryAndAst(
continue
}
const name = node.declarations[0].id.name
// const memoryItem = kclManager.programMemory.root[name]
const memoryItem = programMemory.root[name]
const memoryItem = programMemory.get(name)
if (!memoryItem) {
continue
}
programMemoryOverride.root[name] = JSON.parse(JSON.stringify(memoryItem))
const error = programMemoryOverride.set(
name,
JSON.parse(JSON.stringify(memoryItem))
)
if (err(error)) return error
}
return {
truncatedAst,
@ -1900,7 +1896,7 @@ export function sketchGroupFromPathToNode({
)
if (err(_varDec)) return _varDec
const varDec = _varDec.node
const result = programMemory.root[varDec?.id?.name || '']
const result = programMemory.get(varDec?.id?.name || '')
if (result?.type === 'ExtrudeGroup') {
return result.sketchGroup
}

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