Compare commits

..

57 Commits

Author SHA1 Message Date
de74c4eae0 Tweak format changes
Breaking line(endAbsolute) onto multiple lines changed a bunch of tests
2025-02-11 09:59:48 -06:00
8972ddb640 Merge branch 'nadro/adhoc/ubuntu-e2e-local-fixes' into achalmers/kw-pattern-with-kevin-merge 2025-02-11 09:10:35 -06:00
8a62869d1d fix: restoring this testing code 2025-02-11 08:38:57 -06:00
033687924a Update snapshots 2025-02-10 18:14:24 -06:00
92ed9e445d A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-10 23:37:31 +00:00
2c2974c082 A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-10 23:19:57 +00:00
999897102c Update another example 2025-02-10 17:07:14 -06:00
ac69b1263f Format the helix_simple example 2025-02-10 16:56:28 -06:00
026e45895e Update kcl sim tests 2025-02-10 16:54:18 -06:00
220a49b52b Fix up executor tests 2025-02-10 16:54:17 -06:00
e9862e7677 Redo docs 2025-02-10 16:54:17 -06:00
99cb8d3eb0 Fix clippy 2025-02-10 16:54:17 -06:00
4e2a200bdf Fix unit tests 2025-02-10 16:54:17 -06:00
d95d4d7f66 Use newer branch of kcl-samples 2025-02-10 16:54:17 -06:00
5edfae961e Regn docs 2025-02-10 16:54:16 -06:00
6075aa1d07 Tweak format 2025-02-10 16:54:16 -06:00
75f996e0ef Update test code 2025-02-10 16:54:16 -06:00
d29d2d4a11 WIP: Move patterns to kwargs 2025-02-10 16:54:14 -06:00
33287d540d Merge branch 'main' into nadro/adhoc/ubuntu-e2e-local-fixes 2025-02-10 10:54:41 -06:00
66fe3c7892 fix: auto fix: 2025-02-10 10:21:31 -06:00
3085b0c2c7 chore: skipping one more local engine tests that fails 2025-02-10 10:18:28 -06:00
ff884153db fix: big if true 2025-02-07 16:46:07 -06:00
bcd52a43ca fix: codespell 2025-02-07 16:10:39 -06:00
83ee6511be fix: merging main? 2025-02-07 16:08:03 -06:00
c1ff258bf9 fix: fixing test when using local engine 2025-02-07 14:36:33 -06:00
1469c685c0 chore: adding a skipLocalEngine tag 2025-02-07 11:00:03 -06:00
b2fea24fc4 fix: trying to resolve more flakes when running with more workers 2025-02-06 20:33:43 -06:00
1829c1047a fix: last wait fix 2025-02-06 15:52:52 -06:00
d5c7a1cef3 fix: Fixed testing selections with wait 2025-02-06 15:49:09 -06:00
23ea59cf58 Merge branch 'nadro/adhoc/ubuntu-e2e-local-fixes' of github.com:KittyCAD/modeling-app into nadro/adhoc/ubuntu-e2e-local-fixes 2025-02-06 15:44:56 -06:00
3d6fb4e6e6 fix: bad prompt fix 2025-02-06 15:44:06 -06:00
157ee93032 A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-06 20:46:06 +00:00
6c4c59ced9 A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-06 20:38:33 +00:00
925cc892a7 A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-06 20:30:09 +00:00
08ae896b65 A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-06 20:23:17 +00:00
2073df8a3f A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-06 20:15:22 +00:00
743732ba15 A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) 2025-02-06 20:07:54 +00:00
b8525ccd61 fix: auto fixes 2025-02-06 14:00:42 -06:00
0188d6c065 fix: resolved main conflicts 2025-02-06 13:58:49 -06:00
ddc7d5b20a fix: restoring name 2025-02-06 13:01:40 -06:00
81c2be78bb fix: not waiting for scene, not waiting for command bar 2025-02-06 13:01:03 -06:00
0f85e85c57 fix: wait for execution done 2025-02-06 12:51:53 -06:00
55a302bd75 fix: wait for execution done 2025-02-06 11:36:48 -06:00
21e710ee41 fix: updating wait for execution 2025-02-06 11:32:10 -06:00
bb51c8d269 fix: adding a wait for execution 2025-02-06 11:27:26 -06:00
d9d970b436 fix: add 1250ms before every progresscmdbar, removed model loaded scene state that is flaky, added toast if someone presses the command bar too quickly 2025-02-06 09:52:09 -06:00
1e9a2e3a1a fix: only fixes the chamfer point and click delete 2025-02-06 09:01:59 -06:00
e9ca2469c5 fix: adding execution done wait 2025-02-06 08:50:48 -06:00
1248623922 fix: adding wait for execution done 2025-02-06 08:47:21 -06:00
49ba5d31c7 fix: removing testing code 2025-02-06 08:44:55 -06:00
af7d0e6b66 fix: added wait for execution done 2025-02-06 08:43:57 -06:00
004898e0c7 fix: saving off debugging... 2025-02-05 15:33:33 -06:00
e7457dac0d fix: adding comment to clarify the gotcha 2025-02-05 12:43:25 -06:00
a8d76950d0 fix: fixing react race condition on parsing numeric literals in command bar on open 2025-02-05 12:34:08 -06:00
2ac836c0b8 fix: bug that desyncs codeManager, executeCode, lspPlugin 2025-02-05 11:07:27 -06:00
25c73aae6c fix: again another wait for execution does not work 2025-02-04 15:05:30 -06:00
65682e755a fix: Needed to increase timeout for this test. waitForExecutionDone does not work since there are errors in the KCL code 2025-02-04 14:47:36 -06:00
136 changed files with 28424 additions and 4009 deletions

View File

@ -1,4 +1,5 @@
NODE_ENV=production
DEV=false
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.zoo.dev
VITE_KC_SITE_BASE_URL=https://zoo.dev

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,14 @@ helix(revolutions: number, angle_start: number, ccw?: bool, radius: number, axis
```js
// Create a helix around the Z axis.
helixPath = helix(angleStart = 0, ccw = true, revolutions = 5, length = 10, radius = 5, axis = 'Z')
helixPath = helix(
angleStart = 0,
ccw = true,
revolutions = 5,
length = 10,
radius = 5,
axis = 'Z',
)
// Create a spring by sweeping around the helix path.
springSketch = startSketchOn('YZ')
@ -49,7 +56,14 @@ helper001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line(end = [0, 10], tag = $edge001)
helixPath = helix(angleStart = 0, ccw = true, revolutions = 5, length = 10, radius = 5, axis = edge001)
helixPath = helix(
angleStart = 0,
ccw = true,
revolutions = 5,
length = 10,
radius = 5,
axis = edge001,
)
// Create a spring by sweeping around the helix path.
springSketch = startSketchOn('XY')
@ -61,12 +75,19 @@ springSketch = startSketchOn('XY')
```js
// Create a helix around a custom axis.
helixPath = helix(angleStart = 0, ccw = true, revolutions = 5, length = 10, radius = 5, axis = {
helixPath = helix(
angleStart = 0,
ccw = true,
revolutions = 5,
length = 10,
radius = 5,
axis = {
custom = {
axis = [0, 0, 1.0],
origin = [0, 0.25, 0]
}
})
},
)
// Create a spring by sweeping around the helix path.
springSketch = startSketchOn('XY')

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ Repeat a 2-dimensional sketch some number of times along a partial or
complete circle some specified number of times. Each object may additionally be rotated along the circle, ensuring orentation of the solid with respect to the center of the circle is maintained.
```js
patternCircular2d(data: CircularPattern2dData, sketch_set: SketchSet) -> [Sketch]
patternCircular2d(sketch_set: SketchSet, instances: integer, center: [number], arc_degrees: number, rotate_duplicates: bool, use_original?: bool) -> [Sketch]
```
@ -17,8 +17,12 @@ patternCircular2d(data: CircularPattern2dData, sketch_set: SketchSet) -> [Sketch
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `data` | [`CircularPattern2dData`](/docs/kcl/types/CircularPattern2dData) | Data for a circular pattern on a 2D sketch. | Yes |
| `sketch_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
| `sketch_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | Which sketch(es) to pattern | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `center` | `[number]` | The center about which to make the pattern. This is a 2D vector. | Yes |
| `arc_degrees` | `number` | The arc angle (in degrees) to place the repetitions. Must be greater than 0. | Yes |
| `rotate_duplicates` | `bool` | Whether or not to rotate the duplicates as they are copied. | Yes |
| `use_original` | `bool` | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
### Returns
@ -34,12 +38,12 @@ exampleSketch = startSketchOn('XZ')
|> line(end = [-1, 0])
|> line(end = [0, -5])
|> close()
|> patternCircular2d({
|> patternCircular2d(
center = [0, 0],
instances = 13,
arcDegrees = 360,
rotateDuplicates = true
}, %)
rotateDuplicates = true,
)
example = extrude(exampleSketch, length = 1)
```

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ Repeat a 2-dimensional sketch along some dimension, with a dynamic amount
of distance between each repetition, some specified number of times.
```js
patternLinear2d(data: LinearPattern2dData, sketch_set: SketchSet, use_original?: bool) -> [Sketch]
patternLinear2d(sketch_set: SketchSet, instances: integer, distance: number, axis: [number], use_original?: bool) -> [Sketch]
```
@ -17,9 +17,11 @@ patternLinear2d(data: LinearPattern2dData, sketch_set: SketchSet, use_original?:
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `data` | [`LinearPattern2dData`](/docs/kcl/types/LinearPattern2dData) | Data for a linear pattern on a 2D sketch. | Yes |
| `sketch_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
| `use_original` | `bool` | | No |
| `sketch_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | The sketch(es) to duplicate | Yes |
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `distance` | `number` | Distance between each repetition. Also known as 'spacing'. | Yes |
| `axis` | `[number]` | The axis of the pattern. A 2D vector. | Yes |
| `use_original` | `bool` | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
### Returns
@ -31,11 +33,7 @@ patternLinear2d(data: LinearPattern2dData, sketch_set: SketchSet, use_original?:
```js
exampleSketch = startSketchOn('XZ')
|> circle({ center = [0, 0], radius = 1 }, %)
|> patternLinear2d({
axis = [1, 0],
instances = 7,
distance = 4
}, %)
|> patternLinear2d(axis = [1, 0], instances = 7, distance = 4)
example = extrude(exampleSketch, length = 1)
```

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -59,7 +59,14 @@ sweepSketch = startSketchOn('XY')
// Create a helix around the Z axis.
helixPath = helix(angleStart = 0, ccw = true, revolutions = 4, length = 10, radius = 5, axis = 'Z')
helixPath = helix(
angleStart = 0,
ccw = true,
revolutions = 4,
length = 10,
radius = 5,
axis = 'Z',
)
// Create a spring by sweeping around the helix path.
springSketch = startSketchOn('YZ')

View File

@ -716,330 +716,6 @@ openSketch = startSketchOn('XY')
})
})
test(`Shift-click to select and deselect edges and faces`, async ({
context,
page,
homePage,
scene,
}) => {
// Code samples
const initialCode = `sketch001 = startSketchOn('XY')
|> startProfileAt([-12, -6], %)
|> line(end = [0, 12])
|> line(end = [24, 0])
|> line(end = [0, -12])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> extrude(%, length = -12)`
// Locators
const upperEdgeLocation = { x: 600, y: 192 }
const lowerEdgeLocation = { x: 600, y: 383 }
const faceLocation = { x: 630, y: 290 }
// Click helpers
const [clickOnUpperEdge] = scene.makeMouseHelpers(
upperEdgeLocation.x,
upperEdgeLocation.y
)
const [clickOnLowerEdge] = scene.makeMouseHelpers(
lowerEdgeLocation.x,
lowerEdgeLocation.y
)
const [clickOnFace] = scene.makeMouseHelpers(faceLocation.x, faceLocation.y)
// Colors
const edgeColorWhite: [number, number, number] = [220, 220, 220] // varies from 192 to 255
const edgeColorYellow: [number, number, number] = [251, 251, 40] // vaies from 12 to 67
const faceColorGray: [number, number, number] = [168, 168, 168]
const faceColorYellow: [number, number, number] = [155, 155, 155]
const tolerance = 40
const timeout = 150
// Setup
await test.step(`Initial test setup`, async () => {
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
// Wait for the scene and stream to load
await scene.expectPixelColor(faceColorGray, faceLocation, tolerance)
})
await test.step('Select and deselect a single edge', async () => {
await test.step('Click the edge', async () => {
await scene.expectPixelColor(
edgeColorWhite,
upperEdgeLocation,
tolerance
)
await clickOnUpperEdge()
await scene.expectPixelColor(
edgeColorYellow,
upperEdgeLocation,
tolerance
)
})
await test.step('Shift-click the same edge to deselect', async () => {
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickOnUpperEdge()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorWhite,
upperEdgeLocation,
tolerance
)
})
})
await test.step('Select and deselect multiple objects', async () => {
await test.step('Select both edges and the face', async () => {
await test.step('Select the upper edge', async () => {
await scene.expectPixelColor(
edgeColorWhite,
upperEdgeLocation,
tolerance
)
await clickOnUpperEdge()
await scene.expectPixelColor(
edgeColorYellow,
upperEdgeLocation,
tolerance
)
})
await test.step('Select the lower edge (Shift-click)', async () => {
await scene.expectPixelColor(
edgeColorWhite,
lowerEdgeLocation,
tolerance
)
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickOnLowerEdge()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorYellow,
lowerEdgeLocation,
tolerance
)
})
await test.step('Select the face (Shift-click)', async () => {
await scene.expectPixelColor(faceColorGray, faceLocation, tolerance)
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickOnFace()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(faceColorYellow, faceLocation, tolerance)
})
})
await test.step('Deselect them one by one', async () => {
await test.step('Deselect the face (Shift-click)', async () => {
await scene.expectPixelColor(faceColorYellow, faceLocation, tolerance)
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickOnFace()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(faceColorGray, faceLocation, tolerance)
})
await test.step('Deselect the lower edge (Shift-click)', async () => {
await scene.expectPixelColor(
edgeColorYellow,
lowerEdgeLocation,
tolerance
)
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickOnLowerEdge()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorWhite,
lowerEdgeLocation,
tolerance
)
})
await test.step('Deselect the upper edge (Shift-click)', async () => {
await scene.expectPixelColor(
edgeColorYellow,
upperEdgeLocation,
tolerance
)
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickOnUpperEdge()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorWhite,
upperEdgeLocation,
tolerance
)
})
})
})
})
test(`Shift-click to select and deselect sketch segments`, async ({
page,
homePage,
scene,
editor,
}) => {
// Locators
const firstPointLocation = { x: 200, y: 100 }
const secondPointLocation = { x: 800, y: 100 }
const thirdPointLocation = { x: 800, y: 400 }
const fristSegmentLocation = { x: 750, y: 100 }
const secondSegmentLocation = { x: 800, y: 150 }
const planeLocation = { x: 700, y: 200 }
// Click helpers
const [clickFirstPoint] = scene.makeMouseHelpers(
firstPointLocation.x,
firstPointLocation.y
)
const [clickSecondPoint] = scene.makeMouseHelpers(
secondPointLocation.x,
secondPointLocation.y
)
const [clickThirdPoint] = scene.makeMouseHelpers(
thirdPointLocation.x,
thirdPointLocation.y
)
const [clickFirstSegment] = scene.makeMouseHelpers(
fristSegmentLocation.x,
fristSegmentLocation.y
)
const [clickSecondSegment] = scene.makeMouseHelpers(
secondSegmentLocation.x,
secondSegmentLocation.y
)
const [clickPlane] = scene.makeMouseHelpers(
planeLocation.x,
planeLocation.y
)
// Colors
const edgeColorWhite: [number, number, number] = [220, 220, 220]
const edgeColorBlue: [number, number, number] = [20, 20, 200]
const backgroundColor: [number, number, number] = [30, 30, 30]
const tolerance = 40
const timeout = 150
// Setup
await test.step(`Initial test setup`, async () => {
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
// Wait for the scene and stream to load
await scene.expectPixelColor(
backgroundColor,
secondPointLocation,
tolerance
)
})
await test.step('Select and deselect a single sketch segment', async () => {
await test.step('Get into sketch mode', async () => {
await editor.closePane()
await page.waitForTimeout(timeout)
await page.getByRole('button', { name: 'Start Sketch' }).click()
await page.waitForTimeout(timeout)
await clickPlane()
await page.waitForTimeout(1000)
})
await test.step('Draw sketch', async () => {
await clickFirstPoint()
await page.waitForTimeout(timeout)
await clickSecondPoint()
await page.waitForTimeout(timeout)
await clickThirdPoint()
await page.waitForTimeout(timeout)
})
await test.step('Deselect line tool', async () => {
const btnLine = page.getByTestId('line')
const btnLineAriaPressed = await btnLine.getAttribute('aria-pressed')
if (btnLineAriaPressed === 'true') {
await btnLine.click()
}
await page.waitForTimeout(timeout)
})
await test.step('Select the first segment', async () => {
await page.waitForTimeout(timeout)
await clickFirstSegment()
await page.waitForTimeout(timeout)
await scene.expectPixelColor(
edgeColorBlue,
fristSegmentLocation,
tolerance
)
await scene.expectPixelColor(
edgeColorWhite,
secondSegmentLocation,
tolerance
)
})
await test.step('Select the second segment (Shift-click)', async () => {
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickSecondSegment()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorBlue,
fristSegmentLocation,
tolerance
)
await scene.expectPixelColor(
edgeColorBlue,
secondSegmentLocation,
tolerance
)
})
await test.step('Deselect the first segment', async () => {
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickFirstSegment()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorWhite,
fristSegmentLocation,
tolerance
)
await scene.expectPixelColor(
edgeColorBlue,
secondSegmentLocation,
tolerance
)
})
await test.step('Deselect the second segment', async () => {
await page.keyboard.down('Shift')
await page.waitForTimeout(timeout)
await clickSecondSegment()
await page.waitForTimeout(timeout)
await page.keyboard.up('Shift')
await scene.expectPixelColor(
edgeColorWhite,
fristSegmentLocation,
tolerance
)
await scene.expectPixelColor(
edgeColorWhite,
secondSegmentLocation,
tolerance
)
})
})
})
test(`Offset plane point-and-click`, async ({
context,
page,

View File

@ -192,11 +192,11 @@ extrude001 = extrude(sketch001, length = 50)
|> line(end = [0, -1])
|> close()
|> extrude(length = 1)
|> patternLinear3d({
axis: [1, 0, 1],
repetitions: 3,
distance: 6
}, %)`
|> patternLinear3d(
axis = [1, 0, 1],
repetitions = 3,
distance = 6,
)`
)
})
await page.setBodyDimensions({ width: 1000, height: 500 })

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -32,6 +32,10 @@ win:
arch:
- x64
- arm64
# - target: msi
# arch:
# - x64
# - arm64
signingHashAlgorithms:
- sha256
sign: "./scripts/sign-win.js"
@ -43,12 +47,15 @@ win:
mimeType: text/vnd.zoo.kcl
description: Zoo KCL File
role: Editor
# msi:
# oneClick: false
# perMachine: true
nsis:
oneClick: false
perMachine: true
allowElevation: true
installerIcon: "assets/icon.ico"
include: "./scripts/installer.nsh"
include: "./installer.nsh"
linux:
artifactName: "${productName}-${version}-${arch}-${os}.${ext}"
target:

View File

@ -85,7 +85,7 @@
"fmt": "prettier --write ./src *.ts *.json *.js ./e2e ./packages",
"fmt-check": "prettier --check ./src *.ts *.json *.js ./e2e ./packages",
"fetch:wasm": "./get-latest-wasm-bundle.sh",
"fetch:samples": "echo \"Fetching latest KCL samples...\" && curl -o public/kcl-samples-manifest-fallback.json https://raw.githubusercontent.com/KittyCAD/kcl-samples/achalmers/kw-appearance/manifest.json",
"fetch:samples": "echo \"Fetching latest KCL samples...\" && curl -o public/kcl-samples-manifest-fallback.json https://raw.githubusercontent.com/KittyCAD/kcl-samples/achalmers/kw-pattern/manifest.json",
"isomorphic-copy-wasm": "(copy src/wasm-lib/pkg/wasm_lib_bg.wasm public || cp src/wasm-lib/pkg/wasm_lib_bg.wasm public)",
"build:wasm-dev": "yarn wasm-prep && (cd src/wasm-lib && wasm-pack build --dev --target web --out-dir pkg && cargo test -p kcl-lib export_bindings) && yarn isomorphic-copy-wasm && yarn fmt",
"build:wasm": "yarn wasm-prep && cd src/wasm-lib && wasm-pack build --release --target web --out-dir pkg && cargo test -p kcl-lib export_bindings && cd ../.. && yarn isomorphic-copy-wasm && yarn fmt",

View File

@ -11,7 +11,6 @@ echo "$PACKAGE" > package.json
# electron-builder.yml
yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/nightly"' electron-builder.yml
yq -i '.appId = "dev.zoo.modeling-app-nightly"' electron-builder.yml
yq -i '.nsis.include = "./scripts/installer-nightly.nsh"' electron-builder.yml
# Release notes
echo "Nightly build $VERSION (commit $COMMIT)" > release-notes.md

View File

@ -1,8 +0,0 @@
!macro preInit
SetRegView 64
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Zoo Modeling App (Nightly)"
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Zoo Modeling App (Nightly)"
SetRegView 32
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Zoo Modeling App (Nightly)"
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\Zoo Modeling App (Nightly)"
!macroend

View File

@ -329,83 +329,11 @@ export const ModelingMachineProvider = ({
otherSelections: [],
}
} else if (setSelections.selection && editorManager.isShiftDown) {
// selecting and deselecting multiple objects
/**
* There are two scenarios:
* 1. General case:
* When selecting and deselecting edges,
* faces or segment (during sketch edit)
* we use its artifact ID to identify the selection
* 2. Initial sketch setup:
* The artifact is not yet created
* so we use the codeRef.range
*/
let updatedSelections: typeof selectionRanges.graphSelections
// 1. General case: Artifact exists, use its ID
if (setSelections.selection.artifact?.id) {
// check if already selected
const alreadySelected = selectionRanges.graphSelections.some(
(selection) =>
selection.artifact?.id ===
setSelections.selection?.artifact?.id
)
if (
alreadySelected &&
setSelections.selection?.artifact?.id
) {
// remove it
updatedSelections = selectionRanges.graphSelections.filter(
(selection) =>
selection.artifact?.id !==
setSelections.selection?.artifact?.id
)
} else {
// add it
updatedSelections = [
...selectionRanges.graphSelections,
setSelections.selection,
]
}
} else {
// 2. Initial sketch setup: Artifact not yet created use codeRef.range
const selectionRange = JSON.stringify(
setSelections.selection?.codeRef?.range
)
// check if already selected
const alreadySelected = selectionRanges.graphSelections.some(
(selection) => {
const existingRange = JSON.stringify(
selection.codeRef?.range
)
return existingRange === selectionRange
}
)
if (
alreadySelected &&
setSelections.selection?.codeRef?.range
) {
// remove it
updatedSelections = selectionRanges.graphSelections.filter(
(selection) =>
JSON.stringify(selection.codeRef?.range) !==
selectionRange
)
} else {
// add it
updatedSelections = [
...selectionRanges.graphSelections,
setSelections.selection,
]
}
}
selections = {
graphSelections: updatedSelections,
graphSelections: [
...selectionRanges.graphSelections,
setSelections.selection,
],
otherSelections: selectionRanges.otherSelections,
}
}

View File

@ -58,7 +58,6 @@ export class KclManager {
nonCodeNodes: {},
startNodes: [],
},
trivia: [],
}
private _execState: ExecState = emptyExecState()
private _programMemory: ProgramMemory = ProgramMemory.empty()
@ -240,7 +239,6 @@ export class KclManager {
nonCodeNodes: {},
startNodes: [],
},
trivia: [],
}
}

View File

@ -32,7 +32,7 @@ child_process.spawnSync('git', [
'clone',
'--single-branch',
'--branch',
'achalmers/kw-appearance',
'achalmers/kw-pattern',
URL_GIT_KCL_SAMPLES,
DIR_KCL_SAMPLES,
])

View File

@ -128,78 +128,15 @@ describe('Testing findUniqueName', () => {
it('should find a unique name', () => {
const result = findUniqueName(
JSON.stringify([
{
type: 'Identifier',
name: 'yo01',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo02',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo03',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo04',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo05',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo06',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo07',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo08',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{
type: 'Identifier',
name: 'yo09',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
},
{ type: 'Identifier', name: 'yo01', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo02', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo03', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo04', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo05', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo06', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo07', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo08', start: 0, end: 0, moduleId: 0 },
{ type: 'Identifier', name: 'yo09', start: 0, end: 0, moduleId: 0 },
] satisfies Node<Identifier>[]),
'yo',
2
@ -217,7 +154,6 @@ describe('Testing addSketchTo', () => {
end: 0,
moduleId: 0,
nonCodeMeta: { nonCodeNodes: {}, startNodes: [] },
trivia: [],
},
'yz'
)

View File

@ -278,7 +278,6 @@ export function mutateObjExpProp(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
})
}
}
@ -891,7 +890,6 @@ export function createLiteral(value: LiteralValue | number): Node<Literal> {
moduleId: 0,
value,
raw,
trivia: [],
}
}
@ -901,7 +899,6 @@ export function createTagDeclarator(value: string): Node<TagDeclarator> {
start: 0,
end: 0,
moduleId: 0,
trivia: [],
value,
}
@ -913,7 +910,6 @@ export function createIdentifier(name: string): Node<Identifier> {
start: 0,
end: 0,
moduleId: 0,
trivia: [],
name,
}
@ -925,7 +921,6 @@ export function createPipeSubstitution(): Node<PipeSubstitution> {
start: 0,
end: 0,
moduleId: 0,
trivia: [],
}
}
@ -938,13 +933,11 @@ export function createCallExpressionStdLib(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
callee: {
type: 'Identifier',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
name,
},
@ -962,13 +955,11 @@ export function createCallExpressionStdLibKw(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
callee: {
type: 'Identifier',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
name,
},
@ -986,13 +977,11 @@ export function createCallExpression(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
callee: {
type: 'Identifier',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
name,
},
@ -1008,7 +997,6 @@ export function createArrayExpression(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
nonCodeMeta: nonCodeMetaEmpty(),
elements,
@ -1023,7 +1011,6 @@ export function createPipeExpression(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
body,
nonCodeMeta: nonCodeMetaEmpty(),
@ -1041,14 +1028,12 @@ export function createVariableDeclaration(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
declaration: {
type: 'VariableDeclarator',
start: 0,
end: 0,
moduleId: 0,
trivia: [],
id: createIdentifier(varName),
init,
@ -1066,7 +1051,6 @@ export function createObjectExpression(properties: {
start: 0,
end: 0,
moduleId: 0,
trivia: [],
nonCodeMeta: nonCodeMetaEmpty(),
properties: Object.entries(properties).map(([key, value]) => ({
@ -1074,7 +1058,6 @@ export function createObjectExpression(properties: {
start: 0,
end: 0,
moduleId: 0,
trivia: [],
key: createIdentifier(key),
value,
@ -1091,7 +1074,6 @@ export function createUnaryExpression(
start: 0,
end: 0,
moduleId: 0,
trivia: [],
operator,
argument,
@ -1108,7 +1090,6 @@ export function createBinaryExpression([left, operator, right]: [
start: 0,
end: 0,
moduleId: 0,
trivia: [],
operator,
left,

View File

@ -289,7 +289,10 @@ describe('testing addTagForSketchOnFace', () => {
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> line(
endAbsolute = [profileStartX(%), profileStartY(%)],
tag = $seg02,
)
|> close()
extrude001 = extrude(sketch001, length = 100)
${insertCode}

View File

@ -1954,7 +1954,6 @@ export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
startNodes: [],
nonCodeNodes: [],
},
trivia: [],
},
pathToNode,
}
@ -2535,8 +2534,6 @@ function addTagKw(): addTagFn {
...primaryCallExp,
start: callExpr.node.start,
end: callExpr.node.end,
moduleId: callExpr.node.moduleId,
trivia: callExpr.node.trivia,
})
}

View File

@ -51,16 +51,16 @@ sketch002 = startSketchOn(sketch001, seg03)
center = [-1.25, 1],
radius = mountingHoleDiameter / 2,
}, %)
|> patternLinear2d({
|> patternLinear2d(
instances = 2,
distance = 2.5,
axis = [-1, 0],
}, %)
|> patternLinear2d({
)
|> patternLinear2d(
instances = 2,
distance = 4,
axis = [0, 1],
}, %)
)
|> extrude(%, length = -thickness-.01)
sketch003 = startSketchOn(sketch001, seg04)
@ -68,11 +68,11 @@ sketch003 = startSketchOn(sketch001, seg04)
center = [1, -1],
radius = mountingHoleDiameter / 2,
}, %)
|> patternLinear2d({
|> patternLinear2d(
instances = 2,
distance = 4,
axis = [1, 0],
}, %)
)
|> extrude(%, length = -thickness-0.1)
`

View File

@ -40,6 +40,7 @@ dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
// default vite values based on mode
process.env.NODE_ENV ??= viteEnv.MODE
process.env.DEV ??= viteEnv.DEV + ''
process.env.BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
process.env.VITE_KC_API_WS_MODELING_URL ??= viteEnv.VITE_KC_API_WS_MODELING_URL
process.env.VITE_KC_API_BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
@ -93,11 +94,12 @@ const createWindow = (pathToOpen?: string, reuse?: boolean): BrowserWindow => {
}
// Deep Link: Case of a cold start from Windows or Linux
const zooProtocolArg = process.argv.find((a) =>
a.startsWith(ZOO_STUDIO_PROTOCOL + '://')
)
if (!pathToOpen && zooProtocolArg) {
pathToOpen = zooProtocolArg
if (
!pathToOpen &&
process.argv.length > 1 &&
process.argv[1].indexOf(ZOO_STUDIO_PROTOCOL + '://') > -1
) {
pathToOpen = process.argv[1]
console.log('Retrieved deep link from argv', pathToOpen)
}

View File

@ -730,7 +730,7 @@ dependencies = [
[[package]]
name = "derive-docs"
version = "0.1.36"
version = "0.1.35"
dependencies = [
"Inflector",
"anyhow",
@ -1712,7 +1712,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.2.35"
version = "0.2.34"
dependencies = [
"anyhow",
"approx 0.5.1",

View File

@ -1,7 +1,7 @@
[package]
name = "derive-docs"
description = "A tool for generating documentation from Rust derive macros"
version = "0.1.36"
version = "0.1.35"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -36,5 +36,11 @@ run-sim-test test_name:
{{cita}} -p kcl-lib -- simulation_tests::{{test_name}}::unparse
TWENTY_TWENTY=overwrite {{cita}} -p kcl-lib -- tests::{{test_name}}::kcl_test_execute
overwrite-sim-test test_name:
EXPECTORATE=overwrite {{cita}} -p kcl-lib -- simulation_tests::{{test_name}}::parse
EXPECTORATE=overwrite {{cita}} -p kcl-lib -- simulation_tests::{{test_name}}::unparse
{{cita}} -p kcl-lib -- tests::{{test_name}}::kcl_test_execute
test:
export RUST_BRACKTRACE="full" && cargo nextest run --workspace --test-threads=1

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-lib"
description = "KittyCAD Language implementation and tools"
version = "0.2.35"
version = "0.2.34"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -944,13 +944,7 @@ mod tests {
let snippet = pattern_fn.to_autocomplete_snippet().unwrap();
assert_eq!(
snippet,
r#"patternCircular3d({
instances = ${0:10},
axis = [${1:3.14}, ${2:3.14}, ${3:3.14}],
center = [${4:3.14}, ${5:3.14}, ${6:3.14}],
arcDegrees = ${7:3.14},
rotateDuplicates = ${8:false},
}, ${9:%})${}"#
r#"patternCircular3d(${0:%}, instances = ${1:10}, axis = [${2:3.14}, ${3:3.14}, ${4:3.14}], center = [${5:3.14}, ${6:3.14}, ${7:3.14}], arc_degrees = ${8:3.14}, rotate_duplicates = ${9:false})${}"#
);
}
@ -1006,11 +1000,7 @@ mod tests {
let snippet = pattern_fn.to_autocomplete_snippet().unwrap();
assert_eq!(
snippet,
r#"patternLinear2d({
instances = ${0:10},
distance = ${1:3.14},
axis = [${2:3.14}, ${3:3.14}],
}, ${4:%})${}"#
r#"patternLinear2d(${0:%}, instances = ${1:10}, distance = ${2:3.14}, axis = [${3:3.14}, ${4:3.14}])${}"#
);
}

View File

@ -5,8 +5,7 @@ use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
use crate::{
execution::{ArtifactCommand, ArtifactGraph, Operation},
lsp::IntoDiagnostic,
source_range::SourceRange,
ModuleId,
source_range::{ModuleId, SourceRange},
};
/// How did the KCL execution fail

View File

@ -10,17 +10,16 @@ use crate::{
annotations,
cad_op::{OpArg, Operation},
state::ModuleState,
BodyType, ExecState, ExecutorContext, KclValue, MemoryFunction, Metadata, ProgramMemory, TagEngineInfo,
TagIdentifier,
BodyType, ExecState, ExecutorContext, KclValue, MemoryFunction, Metadata, ModulePath, ModuleRepr,
ProgramMemory, TagEngineInfo, TagIdentifier,
},
modules::{ModuleId, ModulePath, ModuleRepr},
parsing::ast::types::{
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression,
CallExpressionKw, Expr, FunctionExpression, IfExpression, ImportPath, ImportSelector, ItemVisibility,
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NodeRef, NonCodeValue, ObjectExpression,
PipeExpression, TagDeclarator, UnaryExpression, UnaryOperator,
},
source_range::SourceRange,
source_range::{ModuleId, SourceRange},
std::{
args::{Arg, KwArgs},
FunctionKind,
@ -1769,7 +1768,6 @@ mod test {
start: 0,
end: 0,
module_id: ModuleId::default(),
trivia: Vec::new(),
},
return_type: None,
digest: None,

View File

@ -1,6 +1,6 @@
//! The executor for the AST.
use std::{path::PathBuf, sync::Arc};
use std::{fmt, path::PathBuf, sync::Arc};
use anyhow::Result;
pub use artifact::{Artifact, ArtifactCommand, ArtifactGraph, ArtifactId};
@ -9,9 +9,7 @@ use cache::OldAstState;
pub use cad_op::Operation;
pub use exec_ast::FunctionParam;
pub use geometry::*;
pub(crate) use import::{
import_foreign, send_to_engine as send_import_to_engine, PreImportedGeometry, ZOO_COORD_SYSTEM,
};
pub(crate) use import::{import_foreign, send_to_engine as send_import_to_engine, ZOO_COORD_SYSTEM};
use indexmap::IndexMap;
pub use kcl_value::{KclObjectFields, KclValue, UnitAngle, UnitLen};
use kcmc::{
@ -28,15 +26,15 @@ pub use state::{ExecState, IdGenerator, MetaSettings};
use crate::{
engine::EngineManager,
errors::KclError,
errors::{KclError, KclErrorDetails},
execution::{
artifact::build_artifact_graph,
cache::{CacheInformation, CacheResult},
},
fs::FileManager,
parsing::ast::types::{Expr, FunctionExpression, Node, NodeRef, Program},
fs::{FileManager, FileSystem},
parsing::ast::types::{Expr, FunctionExpression, ImportPath, Node, NodeRef, Program},
settings::types::UnitLength,
source_range::SourceRange,
source_range::{ModuleId, SourceRange},
std::{args::Arg, StdLib},
ExecError, KclErrorWithOutputs,
};
@ -164,6 +162,118 @@ pub enum BodyType {
Block,
}
/// Info about a module. Right now, this is pretty minimal. We hope to cache
/// modules here in the future.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ModuleInfo {
/// The ID of the module.
id: ModuleId,
/// Absolute path of the module's source file.
path: ModulePath,
repr: ModuleRepr,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)]
pub enum ModulePath {
Local(std::path::PathBuf),
Std(String),
}
impl ModulePath {
fn expect_path(&self) -> &std::path::PathBuf {
match self {
ModulePath::Local(p) => p,
_ => unreachable!(),
}
}
pub(crate) async fn source(&self, fs: &FileManager, source_range: SourceRange) -> Result<String, KclError> {
match self {
ModulePath::Local(p) => fs.read_to_string(p, source_range).await,
ModulePath::Std(_) => unimplemented!(),
}
}
pub(crate) fn from_import_path(path: &ImportPath, project_directory: &Option<PathBuf>) -> Self {
match path {
ImportPath::Kcl { filename: path } | ImportPath::Foreign { path } => {
let resolved_path = if let Some(project_dir) = project_directory {
project_dir.join(path)
} else {
std::path::PathBuf::from(path)
};
ModulePath::Local(resolved_path)
}
ImportPath::Std { path } => {
// For now we only support importing from singly-nested modules inside std.
assert_eq!(path.len(), 2);
assert_eq!(&path[0], "std");
ModulePath::Std(path[1].clone())
}
}
}
}
impl fmt::Display for ModulePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ModulePath::Local(path) => path.display().fmt(f),
ModulePath::Std(s) => write!(f, "std::{s}"),
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum ModuleRepr {
Root,
Kcl(Node<Program>),
Foreign(import::PreImportedGeometry),
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ModuleLoader {
/// The stack of import statements for detecting circular module imports.
/// If this is empty, we're not currently executing an import statement.
pub import_stack: Vec<PathBuf>,
}
impl ModuleLoader {
pub(crate) fn cycle_check(&self, path: &ModulePath, source_range: SourceRange) -> Result<(), KclError> {
if self.import_stack.contains(path.expect_path()) {
return Err(KclError::ImportCycle(KclErrorDetails {
message: format!(
"circular import of modules is not allowed: {} -> {}",
self.import_stack
.iter()
.map(|p| p.as_path().to_string_lossy())
.collect::<Vec<_>>()
.join(" -> "),
path,
),
source_ranges: vec![source_range],
}));
}
Ok(())
}
pub(crate) fn enter_module(&mut self, path: &ModulePath) {
if let ModulePath::Local(ref path) = path {
self.import_stack.push(path.clone());
}
}
pub(crate) fn leave_module(&mut self, path: &ModulePath) {
if let ModulePath::Local(ref path) = path {
let popped = self.import_stack.pop().unwrap();
assert_eq!(path, &popped);
}
}
}
/// Metadata.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq, Copy)]
#[ts(export)]
@ -774,7 +884,7 @@ mod tests {
use pretty_assertions::assert_eq;
use super::*;
use crate::{errors::KclErrorDetails, ModuleId};
use crate::errors::KclErrorDetails;
/// Convenience function to get a JSON value from memory and unwrap.
#[track_caller]

View File

@ -9,11 +9,11 @@ use crate::{
errors::{KclError, KclErrorDetails},
execution::{
annotations, kcl_value, Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, ExecOutcome, ExecutorSettings,
KclValue, Operation, ProgramMemory, SolidLazyIds, UnitAngle, UnitLen,
KclValue, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, Operation, ProgramMemory, SolidLazyIds, UnitAngle,
UnitLen,
},
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr},
parsing::ast::types::NonCodeValue,
source_range::SourceRange,
source_range::{ModuleId, SourceRange},
};
/// State for executing a program.

View File

@ -65,7 +65,6 @@ mod fs;
pub mod lint;
mod log;
mod lsp;
mod modules;
mod parsing;
mod settings;
#[cfg(test)]
@ -88,10 +87,9 @@ pub use lsp::{
copilot::Backend as CopilotLspBackend,
kcl::{Backend as KclLspBackend, Server as KclLspServerSubCommand},
};
pub use modules::ModuleId;
pub use parsing::ast::{modify::modify_ast_for_sketch, types::FormatOptions};
pub use settings::types::{project::ProjectConfiguration, Configuration, UnitLength};
pub use source_range::SourceRange;
pub use source_range::{ModuleId, SourceRange};
// Rather than make executor public and make lots of it pub(crate), just re-export into a new module.
// Ideally we wouldn't export these things at all, they should only be used for testing.

View File

@ -1543,13 +1543,13 @@ sphere = startSketchOn('XZ')
}, %)
|> close()
|> revolve({ axis: 'x' }, %)
|> patternCircular3d({
axis: [0, 0, 1],
center: [0, 0, 0],
repetitions: 10,
arcDegrees: 360,
rotateDuplicates: true
}, %)
|> patternCircular3d(
axis = [0, 0, 1],
center = [0, 0, 0],
repetitions = 10,
arcDegrees = 360,
rotateDuplicates = true,
)
// Sketch and revolve the outside bearing
outsideRevolve = startSketchOn('XZ')
@ -1644,13 +1644,13 @@ sphere = startSketchOn('XZ')
}, %)
|> close()
|> revolve({ axis = 'x' }, %)
|> patternCircular3d({
|> patternCircular3d(
axis = [0, 0, 1],
center = [0, 0, 0],
repetitions = 10,
arcDegrees = 360,
rotateDuplicates = true
}, %)
rotateDuplicates = true,
)
// Sketch and revolve the outside bearing
outsideRevolve = startSketchOn('XZ')

View File

@ -1,157 +0,0 @@
use std::{fmt, path::PathBuf};
use anyhow::Result;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
errors::{KclError, KclErrorDetails},
execution::PreImportedGeometry,
fs::{FileManager, FileSystem},
parsing::ast::types::{ImportPath, Node, Program},
source_range::SourceRange,
};
/// Identifier of a source file. Uses a u32 to keep the size small.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
#[ts(export)]
pub struct ModuleId(u32);
impl ModuleId {
pub fn from_usize(id: usize) -> Self {
Self(u32::try_from(id).expect("module ID should fit in a u32"))
}
pub fn as_usize(&self) -> usize {
usize::try_from(self.0).expect("module ID should fit in a usize")
}
/// Top-level file is the one being executed.
/// Represented by module ID of 0, i.e. the default value.
pub fn is_top_level(&self) -> bool {
*self == Self::default()
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ModuleLoader {
/// The stack of import statements for detecting circular module imports.
/// If this is empty, we're not currently executing an import statement.
pub import_stack: Vec<PathBuf>,
}
impl ModuleLoader {
pub(crate) fn cycle_check(&self, path: &ModulePath, source_range: SourceRange) -> Result<(), KclError> {
if self.import_stack.contains(path.expect_path()) {
return Err(KclError::ImportCycle(KclErrorDetails {
message: format!(
"circular import of modules is not allowed: {} -> {}",
self.import_stack
.iter()
.map(|p| p.as_path().to_string_lossy())
.collect::<Vec<_>>()
.join(" -> "),
path,
),
source_ranges: vec![source_range],
}));
}
Ok(())
}
pub(crate) fn enter_module(&mut self, path: &ModulePath) {
if let ModulePath::Local(ref path) = path {
self.import_stack.push(path.clone());
}
}
pub(crate) fn leave_module(&mut self, path: &ModulePath) {
if let ModulePath::Local(ref path) = path {
let popped = self.import_stack.pop().unwrap();
assert_eq!(path, &popped);
}
}
}
pub(crate) fn read_std(_mod_name: &str) -> Option<&'static str> {
None
}
/// Info about a module. Right now, this is pretty minimal. We hope to cache
/// modules here in the future.
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ModuleInfo {
/// The ID of the module.
pub(crate) id: ModuleId,
/// Absolute path of the module's source file.
pub(crate) path: ModulePath,
pub(crate) repr: ModuleRepr,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum ModuleRepr {
Root,
Kcl(Node<Program>),
Foreign(PreImportedGeometry),
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)]
pub enum ModulePath {
Local(PathBuf),
Std(String),
}
impl ModulePath {
pub(crate) fn expect_path(&self) -> &PathBuf {
match self {
ModulePath::Local(p) => p,
_ => unreachable!(),
}
}
pub(crate) async fn source(&self, fs: &FileManager, source_range: SourceRange) -> Result<String, KclError> {
match self {
ModulePath::Local(p) => fs.read_to_string(p, source_range).await,
ModulePath::Std(name) => read_std(name)
.ok_or_else(|| {
KclError::Semantic(KclErrorDetails {
message: format!("Cannot find standard library module to import: std::{name}."),
source_ranges: vec![source_range],
})
})
.map(str::to_owned),
}
}
pub(crate) fn from_import_path(path: &ImportPath, project_directory: &Option<PathBuf>) -> Self {
match path {
ImportPath::Kcl { filename: path } | ImportPath::Foreign { path } => {
let resolved_path = if let Some(project_dir) = project_directory {
project_dir.join(path)
} else {
std::path::PathBuf::from(path)
};
ModulePath::Local(resolved_path)
}
ImportPath::Std { path } => {
// For now we only support importing from singly-nested modules inside std.
assert_eq!(path.len(), 2);
assert_eq!(&path[0], "std");
ModulePath::Std(path[1].clone())
}
}
}
}
impl fmt::Display for ModulePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ModulePath::Local(path) => path.display().fmt(f),
ModulePath::Std(s) => write!(f, "std::{s}"),
}
}
}

View File

@ -4,7 +4,7 @@ pub mod types;
use crate::{
parsing::ast::types::{BinaryPart, BodyItem, Expr, LiteralIdentifier, MemberObject},
ModuleId,
source_range::ModuleId,
};
impl BodyItem {

View File

@ -15,8 +15,8 @@ use crate::{
ArrayExpression, CallExpression, ConstraintLevel, FormatOptions, Literal, Node, PipeExpression,
PipeSubstitution, VariableDeclarator,
},
source_range::SourceRange,
ModuleId, Program,
source_range::{ModuleId, SourceRange},
Program,
};
type Point3d = kcmc::shared::Point3d<f64>;

View File

@ -28,8 +28,7 @@ use crate::{
execution::{annotations, KclValue, Metadata, TagIdentifier},
parsing::{ast::digest::Digest, PIPE_OPERATOR},
pretty::NumericSuffix,
source_range::SourceRange,
ModuleId,
source_range::{ModuleId, SourceRange},
};
mod condition;
@ -41,7 +40,7 @@ pub enum Definition<'a> {
Import(NodeRef<'a, ImportStatement>),
}
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS)]
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct Node<T> {
@ -51,8 +50,6 @@ pub struct Node<T> {
pub end: usize,
#[serde(default, skip_serializing_if = "ModuleId::is_top_level")]
pub module_id: ModuleId,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub trivia: NodeList<NonCodeNode>,
}
impl<T> Node<T> {
@ -96,7 +93,6 @@ impl<T> Node<T> {
start,
end,
module_id,
trivia: Vec::new(),
}
}
@ -106,7 +102,6 @@ impl<T> Node<T> {
start: 0,
end: 0,
module_id: ModuleId::default(),
trivia: Vec::new(),
}
}
@ -116,7 +111,6 @@ impl<T> Node<T> {
start,
end,
module_id,
trivia: Vec::new(),
})
}
@ -647,7 +641,6 @@ impl From<&BodyItem> for SourceRange {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
#[allow(clippy::large_enum_variant)]
pub enum Expr {
Literal(BoxNode<Literal>),
Identifier(BoxNode<Identifier>),
@ -3829,7 +3822,6 @@ const cylinder = startSketchOn('-XZ')
start: 0,
end: 0,
module_id: ModuleId::default(),
trivia: Vec::new(),
},
return_type: None,
digest: None,
@ -3859,7 +3851,6 @@ const cylinder = startSketchOn('-XZ')
start: 0,
end: 0,
module_id: ModuleId::default(),
trivia: Vec::new(),
},
return_type: None,
digest: None,
@ -3901,7 +3892,6 @@ const cylinder = startSketchOn('-XZ')
start: 0,
end: 0,
module_id: ModuleId::default(),
trivia: Vec::new(),
},
return_type: None,
digest: None,

View File

@ -131,7 +131,7 @@ mod tests {
ast::types::{Literal, LiteralValue},
token::NumericSuffix,
},
ModuleId,
source_range::ModuleId,
};
#[test]

View File

@ -4,8 +4,7 @@ use crate::{
ast::types::{Node, Program},
token::TokenStream,
},
source_range::SourceRange,
ModuleId,
source_range::{ModuleId, SourceRange},
};
pub(crate) mod ast;

View File

@ -308,7 +308,6 @@ fn annotation(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
value,
digest: None,
},
trivia: Vec::new(),
}),
comma_sep,
)
@ -427,7 +426,6 @@ fn pipe_expression(i: &mut TokenSlice) -> PResult<Node<PipeExpression>> {
non_code_meta,
digest: None,
},
trivia: Vec::new(),
})
}
@ -830,7 +828,6 @@ fn object_property_same_key_and_val(i: &mut TokenSlice) -> PResult<Node<ObjectPr
key,
digest: None,
},
trivia: Vec::new(),
})
}
@ -859,7 +856,6 @@ fn object_property(i: &mut TokenSlice) -> PResult<Node<ObjectProperty>> {
value: expr,
digest: None,
},
trivia: Vec::new(),
};
if sep.token_type == TokenType::Colon {
@ -1790,7 +1786,6 @@ fn return_stmt(i: &mut TokenSlice) -> PResult<Node<ReturnStatement>> {
end: argument.end(),
module_id: ret.module_id,
inner: ReturnStatement { argument, digest: None },
trivia: Vec::new(),
})
}
@ -2017,13 +2012,11 @@ fn declaration(i: &mut TokenSlice) -> PResult<BoxNode<VariableDeclaration>> {
init: val,
digest: None,
},
trivia: Vec::new(),
},
visibility,
kind,
digest: None,
},
trivia: Vec::new(),
}))
}
@ -2229,7 +2222,6 @@ fn unary_expression(i: &mut TokenSlice) -> PResult<Node<UnaryExpression>> {
argument,
digest: None,
},
trivia: Vec::new(),
})
}
@ -2310,7 +2302,6 @@ fn expression_stmt(i: &mut TokenSlice) -> PResult<Node<ExpressionStatement>> {
expression: val,
digest: None,
},
trivia: Vec::new(),
})
}
@ -2750,7 +2741,6 @@ fn fn_call(i: &mut TokenSlice) -> PResult<Node<CallExpression>> {
arguments: args,
digest: None,
},
trivia: Vec::new(),
})
}
@ -2780,7 +2770,6 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
arguments: args,
digest: None,
},
trivia: Vec::new(),
})
}

View File

@ -1,6 +1,8 @@
---
source: kcl/src/parsing/parser.rs
assertion_line: 4521
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -1,6 +1,8 @@
---
source: kcl/src/parsing/parser.rs
assertion_line: 4522
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -1,6 +1,8 @@
---
source: kcl/src/parsing/parser.rs
assertion_line: 4523
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -1,6 +1,8 @@
---
source: kcl/src/parsing/parser.rs
assertion_line: 4524
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -1,6 +1,8 @@
---
source: kcl/src/parsing/parser.rs
assertion_line: 4525
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/parsing/parser.rs
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/parsing/parser.rs
expression: actual
snapshot_kind: text
---
{
"body": [

View File

@ -18,8 +18,8 @@ use winnow::{
use crate::{
errors::KclError,
parsing::ast::types::{ItemVisibility, VariableKind},
source_range::SourceRange,
CompilationError, ModuleId,
source_range::{ModuleId, SourceRange},
CompilationError,
};
mod tokeniser;

View File

@ -13,7 +13,7 @@ use winnow::{
use super::TokenStream;
use crate::{
parsing::token::{Token, TokenType},
ModuleId,
source_range::ModuleId,
};
lazy_static! {

View File

@ -7,7 +7,7 @@ use crate::{
exec::ArtifactCommand,
execution::{ArtifactGraph, Operation},
parsing::ast::types::{Node, Program},
ModuleId,
source_range::ModuleId,
};
/// Deserialize the data from a snapshot.

View File

@ -2,7 +2,26 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
use crate::modules::ModuleId;
/// Identifier of a source file. Uses a u32 to keep the size small.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
#[ts(export)]
pub struct ModuleId(u32);
impl ModuleId {
pub fn from_usize(id: usize) -> Self {
Self(u32::try_from(id).expect("module ID should fit in a u32"))
}
pub fn as_usize(&self) -> usize {
usize::try_from(self.0).expect("module ID should fit in a usize")
}
/// Top-level file is the one being executed.
/// Represented by module ID of 0, i.e. the default value.
pub fn is_top_level(&self) -> bool {
*self == Self::default()
}
}
/// The first two items are the start and end points (byte offsets from the start of the file).
/// The third item is whether the source range belongs to the 'main' file, i.e., the file currently

View File

@ -180,12 +180,12 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
/// color = '#ff0000',
/// metalness = 90,
/// roughness = 90
/// )
/// |> patternLinear3d({
/// axis = [1, 0, 1],
/// instances = 7,
/// distance = 6
/// }, %)
/// )
/// |> patternLinear3d(
/// axis = [1, 0, 1],
/// instances = 7,
/// distance = 6
/// )
/// ```
///
/// ```no_run
@ -199,16 +199,16 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
/// |> close()
///
/// example = extrude(exampleSketch, length = 1)
/// |> patternLinear3d({
/// |> patternLinear3d(
/// axis = [1, 0, 1],
/// instances = 7,
/// distance = 6
/// }, %)
/// |> appearance(
/// color = '#ff0000',
/// metalness = 90,
/// roughness = 90
/// )
/// )
/// |> appearance(
/// color = '#ff0000',
/// metalness = 90,
/// roughness = 90
/// )
/// ```
///
/// ```no_run
@ -219,12 +219,12 @@ pub async fn appearance(_exec_state: &mut ExecState, args: Args) -> Result<KclVa
/// |> line(end = [-1, 0])
/// |> line(end = [0, -5])
/// |> close()
/// |> patternCircular2d({
/// |> patternCircular2d(
/// center = [0, 0],
/// instances = 13,
/// arcDegrees = 360,
/// rotateDuplicates = true
/// }, %)
/// )
///
/// example = extrude(exampleSketch, length = 1)
/// |> appearance(

View File

@ -440,13 +440,6 @@ impl Args {
FromArgs::from_args(self, 0)
}
pub(crate) fn get_data_and_solid_set<'a, T>(&'a self) -> Result<(T, SolidSet), KclError>
where
T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
{
FromArgs::from_args(self, 0)
}
pub(crate) fn get_data_and_solid<'a, T>(&'a self) -> Result<(T, Box<Solid>), KclError>
where
T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
@ -943,72 +936,6 @@ impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::Direction {
}
}
impl<'a> FromKclValue<'a> for super::patterns::CircularPattern3dData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, instances);
let_field_of!(obj, arc_degrees "arcDegrees");
let_field_of!(obj, rotate_duplicates "rotateDuplicates");
let_field_of!(obj, axis);
let_field_of!(obj, center);
let_field_of!(obj, use_original? "useOriginal");
Some(Self {
instances,
axis,
center,
arc_degrees,
rotate_duplicates,
use_original,
})
}
}
impl<'a> FromKclValue<'a> for super::patterns::CircularPattern2dData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, instances);
let_field_of!(obj, arc_degrees "arcDegrees");
let_field_of!(obj, rotate_duplicates "rotateDuplicates");
let_field_of!(obj, center);
let_field_of!(obj, use_original? "useOriginal");
Some(Self {
instances,
center,
arc_degrees,
rotate_duplicates,
use_original,
})
}
}
impl<'a> FromKclValue<'a> for super::patterns::LinearPattern3dData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, distance);
let_field_of!(obj, instances);
let_field_of!(obj, axis);
Some(Self {
instances,
distance,
axis,
})
}
}
impl<'a> FromKclValue<'a> for super::patterns::LinearPattern2dData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, distance);
let_field_of!(obj, instances);
let_field_of!(obj, axis);
Some(Self {
instances,
distance,
axis,
})
}
}
impl<'a> FromKclValue<'a> for super::sketch::BezierData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;

View File

@ -29,22 +29,6 @@ use crate::{
const MUST_HAVE_ONE_INSTANCE: &str = "There must be at least 1 instance of your geometry";
/// Data for a linear pattern on a 2D sketch.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct LinearPattern2dData {
/// The number of total instances. Must be greater than or equal to 1.
/// This includes the original entity. For example, if instances is 2,
/// there will be two copies -- the original, and one new copy.
/// If instances is 1, this has no effect.
pub instances: u32,
/// The distance between each repetition. This can also be referred to as spacing.
pub distance: f64,
/// The axis of the pattern. This is a 2D vector.
pub axis: [f64; 2],
}
/// Data for a linear pattern on a 3D model.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
@ -689,10 +673,13 @@ mod tests {
/// A linear pattern on a 2D sketch.
pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch_set, use_original): (LinearPattern2dData, SketchSet, Option<bool>) =
super::args::FromArgs::from_args(&args, 0)?;
let sketch_set: SketchSet = args.get_unlabeled_kw_arg("sketchSet")?;
let instances: u32 = args.get_kw_arg("instances")?;
let distance: f64 = args.get_kw_arg("distance")?;
let axis: [f64; 2] = args.get_kw_arg("axis")?;
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
if data.axis == [0.0, 0.0] {
if axis == [0.0, 0.0] {
return Err(KclError::Semantic(KclErrorDetails {
message:
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
@ -701,7 +688,8 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
}));
}
let sketches = inner_pattern_linear_2d(data, sketch_set, use_original, exec_state, args).await?;
let sketches =
inner_pattern_linear_2d(sketch_set, instances, distance, axis, use_original, exec_state, args).await?;
Ok(sketches.into())
}
@ -711,31 +699,41 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
/// ```no_run
/// exampleSketch = startSketchOn('XZ')
/// |> circle({ center = [0, 0], radius = 1 }, %)
/// |> patternLinear2d({
/// |> patternLinear2d(
/// axis = [1, 0],
/// instances = 7,
/// distance = 4
/// }, %)
/// )
///
/// example = extrude(exampleSketch, length = 1)
/// ```
#[stdlib {
name = "patternLinear2d",
keywords = true,
unlabeled_first = true,
args = {
sketch_set = { docs = "The sketch(es) to duplicate" },
instances = { docs = "The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect." },
distance = { docs = "Distance between each repetition. Also known as 'spacing'."},
axis = { docs = "The axis of the pattern. A 2D vector." },
use_original = { docs = "If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false." },
}
}]
async fn inner_pattern_linear_2d(
data: LinearPattern2dData,
sketch_set: SketchSet,
instances: u32,
distance: f64,
axis: [f64; 2],
use_original: Option<bool>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Box<Sketch>>, KclError> {
let axis = data.axis;
let [x, y] = axis;
let axis_len = f64::sqrt(x * x + y * y);
let normalized_axis = kcmc::shared::Point2d::from([x / axis_len, y / axis_len]);
let transforms: Vec<_> = (1..data.instances)
let transforms: Vec<_> = (1..instances)
.map(|i| {
let d = data.distance * (i as f64);
let d = distance * (i as f64);
let translate = (normalized_axis * d).with_z(0.0).map(LengthUnit);
vec![Transform {
translate,
@ -755,10 +753,13 @@ async fn inner_pattern_linear_2d(
/// A linear pattern on a 3D model.
pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, solid_set, use_original): (LinearPattern3dData, SolidSet, Option<bool>) =
super::args::FromArgs::from_args(&args, 0)?;
let solid_set: SolidSet = args.get_unlabeled_kw_arg("solidSet")?;
let instances: u32 = args.get_kw_arg("instances")?;
let distance: f64 = args.get_kw_arg("distance")?;
let axis: [f64; 3] = args.get_kw_arg("axis")?;
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
if data.axis == [0.0, 0.0, 0.0] {
if axis == [0.0, 0.0, 0.0] {
return Err(KclError::Semantic(KclErrorDetails {
message:
"The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
@ -767,7 +768,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
}));
}
let solids = inner_pattern_linear_3d(data, solid_set, use_original, exec_state, args).await?;
let solids = inner_pattern_linear_3d(solid_set, instances, distance, axis, use_original, exec_state, args).await?;
Ok(solids.into())
}
@ -783,30 +784,40 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
/// |> close()
///
/// example = extrude(exampleSketch, length = 1)
/// |> patternLinear3d({
/// |> patternLinear3d(
/// axis = [1, 0, 1],
/// instances = 7,
/// distance = 6
/// }, %)
/// )
/// ```
#[stdlib {
name = "patternLinear3d",
feature_tree_operation = true,
keywords = true,
unlabeled_first = true,
args = {
solid_set = { docs = "The solid(s) to duplicate" },
instances = { docs = "The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect." },
distance = { docs = "Distance between each repetition. Also known as 'spacing'."},
axis = { docs = "The axis of the pattern. A 2D vector." },
use_original = { docs = "If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false." },
}
}]
async fn inner_pattern_linear_3d(
data: LinearPattern3dData,
solid_set: SolidSet,
instances: u32,
distance: f64,
axis: [f64; 3],
use_original: Option<bool>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Box<Solid>>, KclError> {
let axis = data.axis;
let [x, y, z] = axis;
let axis_len = f64::sqrt(x * x + y * y + z * z);
let normalized_axis = kcmc::shared::Point3d::from([x / axis_len, y / axis_len, z / axis_len]);
let transforms: Vec<_> = (1..data.instances)
let transforms: Vec<_> = (1..instances)
.map(|i| {
let d = data.distance * (i as f64);
let d = distance * (i as f64);
let translate = (normalized_axis * d).map(LengthUnit);
vec![Transform {
translate,
@ -828,7 +839,7 @@ async fn inner_pattern_linear_3d(
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct CircularPattern2dData {
struct CircularPattern2dData {
/// The number of total instances. Must be greater than or equal to 1.
/// This includes the original entity. For example, if instances is 2,
/// there will be two copies -- the original, and one new copy.
@ -870,7 +881,7 @@ pub struct CircularPattern3dData {
pub use_original: Option<bool>,
}
pub enum CircularPattern {
enum CircularPattern {
ThreeD(CircularPattern3dData),
TwoD(CircularPattern2dData),
}
@ -941,9 +952,24 @@ impl CircularPattern {
/// A circular pattern on a 2D sketch.
pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch_set): (CircularPattern2dData, SketchSet) = args.get_data_and_sketch_set()?;
let sketch_set: SketchSet = args.get_unlabeled_kw_arg("sketchSet")?;
let instances: u32 = args.get_kw_arg("instances")?;
let center: [f64; 2] = args.get_kw_arg("center")?;
let arc_degrees: f64 = args.get_kw_arg("arcDegrees")?;
let rotate_duplicates: bool = args.get_kw_arg("rotateDuplicates")?;
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
let sketches = inner_pattern_circular_2d(data, sketch_set, exec_state, args).await?;
let sketches = inner_pattern_circular_2d(
sketch_set,
instances,
center,
arc_degrees,
rotate_duplicates,
use_original,
exec_state,
args,
)
.await?;
Ok(sketches.into())
}
@ -959,21 +985,36 @@ pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Resu
/// |> line(end = [-1, 0])
/// |> line(end = [0, -5])
/// |> close()
/// |> patternCircular2d({
/// |> patternCircular2d(
/// center = [0, 0],
/// instances = 13,
/// arcDegrees = 360,
/// rotateDuplicates = true
/// }, %)
/// )
///
/// example = extrude(exampleSketch, length = 1)
/// ```
#[stdlib {
name = "patternCircular2d",
keywords = true,
unlabeled_first = true,
args = {
sketch_set = { docs = "Which sketch(es) to pattern" },
instances = { docs = "The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect."},
center = { docs = "The center about which to make the pattern. This is a 2D vector."},
arc_degrees = { docs = "The arc angle (in degrees) to place the repetitions. Must be greater than 0."},
rotate_duplicates= { docs = "Whether or not to rotate the duplicates as they are copied."},
use_original= { docs = "If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false."},
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_pattern_circular_2d(
data: CircularPattern2dData,
sketch_set: SketchSet,
instances: u32,
center: [f64; 2],
arc_degrees: f64,
rotate_duplicates: bool,
use_original: Option<bool>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Box<Sketch>>, KclError> {
@ -982,6 +1023,13 @@ async fn inner_pattern_circular_2d(
if args.ctx.context_type == crate::execution::ContextType::Mock {
return Ok(starting_sketches);
}
let data = CircularPattern2dData {
instances,
center,
arc_degrees,
rotate_duplicates,
use_original,
};
let mut sketches = Vec::new();
for sketch in starting_sketches.iter() {
@ -1008,9 +1056,36 @@ async fn inner_pattern_circular_2d(
/// A circular pattern on a 3D model.
pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, solid_set): (CircularPattern3dData, SolidSet) = args.get_data_and_solid_set()?;
let solid_set: SolidSet = args.get_unlabeled_kw_arg("solidSet")?;
// The number of total instances. Must be greater than or equal to 1.
// This includes the original entity. For example, if instances is 2,
// there will be two copies -- the original, and one new copy.
// If instances is 1, this has no effect.
let instances: u32 = args.get_kw_arg("instances")?;
// The axis around which to make the pattern. This is a 3D vector.
let axis: [f64; 3] = args.get_kw_arg("axis")?;
// The center about which to make the pattern. This is a 3D vector.
let center: [f64; 3] = args.get_kw_arg("center")?;
// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
let arc_degrees: f64 = args.get_kw_arg("arcDegrees")?;
// Whether or not to rotate the duplicates as they are copied.
let rotate_duplicates: bool = args.get_kw_arg("rotateDuplicates")?;
// If the target being patterned is itself a pattern, then, should you use the original solid,
// or the pattern?
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
let solids = inner_pattern_circular_3d(data, solid_set, exec_state, args).await?;
let solids = inner_pattern_circular_3d(
solid_set,
instances,
axis,
center,
arc_degrees,
rotate_duplicates,
use_original,
exec_state,
args,
)
.await?;
Ok(solids.into())
}
@ -1024,21 +1099,38 @@ pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Resu
/// |> circle({ center = [0, 0], radius = 1 }, %)
///
/// example = extrude(exampleSketch, length = -5)
/// |> patternCircular3d({
/// |> patternCircular3d(
/// axis = [1, -1, 0],
/// center = [10, -20, 0],
/// instances = 11,
/// arcDegrees = 360,
/// rotateDuplicates = true
/// }, %)
/// )
/// ```
#[stdlib {
name = "patternCircular3d",
feature_tree_operation = true,
keywords = true,
unlabeled_first = true,
args = {
solid_set = { docs = "Which solid(s) to pattern" },
instances = { docs = "The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect."},
axis = { docs = "The axis around which to make the pattern. This is a 3D vector"},
center = { docs = "The center about which to make the pattern. This is a 3D vector."},
arc_degrees = { docs = "The arc angle (in degrees) to place the repetitions. Must be greater than 0."},
rotate_duplicates= { docs = "Whether or not to rotate the duplicates as they are copied."},
use_original= { docs = "If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false."},
}
}]
#[allow(clippy::too_many_arguments)]
async fn inner_pattern_circular_3d(
data: CircularPattern3dData,
solid_set: SolidSet,
instances: u32,
axis: [f64; 3],
center: [f64; 3],
arc_degrees: f64,
rotate_duplicates: bool,
use_original: Option<bool>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Box<Solid>>, KclError> {
@ -1055,6 +1147,14 @@ async fn inner_pattern_circular_3d(
}
let mut solids = Vec::new();
let data = CircularPattern3dData {
instances,
axis,
center,
arc_degrees,
rotate_duplicates,
use_original,
};
for solid in starting_solids.iter() {
let geometries = pattern_circular(
CircularPattern::ThreeD(data.clone()),

View File

@ -334,8 +334,25 @@ impl CallExpressionKw {
.iter()
.map(|arg| arg.recast(options, indentation_level, ctxt)),
);
let args = arg_list.join(", ");
format!("{indent}{name}({args})")
let args = arg_list.clone().join(", ");
if arg_list.len() >= 4 {
let inner_indentation = if ctxt == ExprContext::Pipe {
options.get_indentation_offset_pipe(indentation_level + 1)
} else {
options.get_indentation(indentation_level + 1)
};
let mut args = arg_list.join(&format!(",\n{inner_indentation}"));
args.push(',');
let args = args;
let end_indent = if ctxt == ExprContext::Pipe {
options.get_indentation_offset_pipe(indentation_level)
} else {
options.get_indentation(indentation_level)
};
format!("{indent}{name}(\n{inner_indentation}{args}\n{end_indent})")
} else {
format!("{indent}{name}({args})")
}
}
}
@ -795,7 +812,7 @@ mod tests {
use pretty_assertions::assert_eq;
use super::*;
use crate::{parsing::ast::types::FormatOptions, ModuleId};
use crate::{parsing::ast::types::FormatOptions, source_range::ModuleId};
#[test]
fn test_recast_if_else_if_same() {
@ -1031,13 +1048,13 @@ sphere = startSketchOn('XZ')
}, %)
|> close()
|> revolve({ axis: 'x' }, %)
|> patternCircular3d({
|> patternCircular3d(
axis = [0, 0, 1],
center = [0, 0, 0],
repetitions = 10,
arcDegrees = 360,
rotateDuplicates = true
}, %)
)
// Sketch and revolve the outside bearing
outsideRevolve = startSketchOn('XZ')
@ -1098,13 +1115,13 @@ sphere = startSketchOn('XZ')
}, %)
|> close()
|> revolve({ axis = 'x' }, %)
|> patternCircular3d({
|> patternCircular3d(
axis = [0, 0, 1],
center = [0, 0, 0],
repetitions = 10,
arcDegrees = 360,
rotateDuplicates = true
}, %)
rotateDuplicates = true,
)
// Sketch and revolve the outside bearing
outsideRevolve = startSketchOn('XZ')
@ -1417,11 +1434,11 @@ tabs_r = startSketchOn({
radius = hole_diam / 2
}, %), %)
|> extrude(-thk, %)
|> patternLinear3d({
|> patternLinear3d(
axis = [0, -1, 0],
repetitions = 1,
distance = length - 10
}, %)
)
// build the tabs of the mounting bracket (left side)
tabs_l = startSketchOn({
plane: {
@ -1444,11 +1461,7 @@ tabs_l = startSketchOn({
radius = hole_diam / 2
}, %), %)
|> extrude(-thk, %)
|> patternLinear3d({
axis = [0, -1, 0],
repetitions = 1,
distance = length - 10
}, %)
|> patternLinear3d(axis = [0, -1, 0], repetitions = 1, distance = length - 10)
"#;
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
@ -1542,11 +1555,7 @@ tabs_r = startSketchOn({
radius = hole_diam / 2
}, %), %)
|> extrude(-thk, %)
|> patternLinear3d({
axis = [0, -1, 0],
repetitions = 1,
distance = length - 10
}, %)
|> patternLinear3d(axis = [0, -1, 0], repetitions = 1, distance = length - 10)
// build the tabs of the mounting bracket (left side)
tabs_l = startSketchOn({
plane = {
@ -1569,11 +1578,7 @@ tabs_l = startSketchOn({
radius = hole_diam / 2
}, %), %)
|> extrude(-thk, %)
|> patternLinear3d({
axis = [0, -1, 0],
repetitions = 1,
distance = length - 10
}, %)
|> patternLinear3d(axis = [0, -1, 0], repetitions = 1, distance = length - 10)
"#
);
}

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing angled_line.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing artifact_graph_example_code1.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing artifact_graph_example_code1.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing artifact_graph_example_code_no_3d.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing artifact_graph_example_code_no_3d.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing artifact_graph_example_code_offset_planes.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing artifact_graph_sketch_on_face_etc.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing artifact_graph_sketch_on_face_etc.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing basic_fillet_cube_close_opposite.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing basic_fillet_cube_end.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing basic_fillet_cube_next_adjacent.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing basic_fillet_cube_previous_adjacent.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing basic_fillet_cube_start.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing big_number_angle_to_match_length_x.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing big_number_angle_to_match_length_x.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing big_number_angle_to_match_length_y.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -631,7 +631,7 @@ snapshot_kind: text
"cmdId": "[uuid]",
"range": [
189,
276,
277,
0
],
"command": {
@ -819,8 +819,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {
@ -844,8 +844,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {
@ -869,8 +869,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {
@ -894,8 +894,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {
@ -919,8 +919,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {
@ -944,8 +944,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {
@ -969,8 +969,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
430,
288,
432,
0
],
"command": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing circular_pattern3d_a_pattern.kcl
snapshot_kind: text
---
{
"Ok": {
@ -321,7 +322,7 @@ description: Result of parsing circular_pattern3d_a_pattern.kcl
},
{
"declaration": {
"end": 276,
"end": 277,
"id": {
"end": 186,
"name": "pattn1",
@ -331,115 +332,88 @@ description: Result of parsing circular_pattern3d_a_pattern.kcl
"init": {
"arguments": [
{
"end": 260,
"properties": [
{
"end": 225,
"key": {
"end": 213,
"name": "axis",
"start": 209,
"type": "Identifier"
},
"start": 209,
"type": "ObjectProperty",
"value": {
"elements": [
{
"end": 218,
"raw": "1",
"start": 217,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
},
{
"end": 221,
"raw": "0",
"start": 220,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"end": 224,
"raw": "0",
"start": 223,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
}
],
"end": 225,
"start": 216,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 242,
"key": {
"end": 238,
"name": "instances",
"start": 229,
"type": "Identifier"
},
"start": 229,
"type": "ObjectProperty",
"value": {
"end": 242,
"raw": "7",
"start": 241,
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "axis"
},
"arg": {
"elements": [
{
"end": 234,
"raw": "1",
"start": 233,
"type": "Literal",
"type": "Literal",
"value": {
"value": 7.0,
"value": 1.0,
"suffix": "None"
}
}
},
{
"end": 258,
"key": {
"end": 254,
"name": "distance",
"start": 246,
"type": "Identifier"
},
"start": 246,
"type": "ObjectProperty",
"value": {
"end": 258,
"raw": "6",
"start": 257,
{
"end": 237,
"raw": "0",
"start": 236,
"type": "Literal",
"type": "Literal",
"value": {
"value": 6.0,
"value": 0.0,
"suffix": "None"
}
},
{
"end": 240,
"raw": "0",
"start": 239,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
}
}
],
"start": 205,
"type": "ObjectExpression",
"type": "ObjectExpression"
],
"end": 241,
"start": 232,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 275,
"name": "exampleSketch",
"start": 262,
"type": "Identifier",
"type": "Identifier"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "instances"
},
"arg": {
"end": 258,
"raw": "7",
"start": 257,
"type": "Literal",
"type": "Literal",
"value": {
"value": 7.0,
"suffix": "None"
}
}
},
{
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "distance"
},
"arg": {
"end": 274,
"raw": "6",
"start": 273,
"type": "Literal",
"type": "Literal",
"value": {
"value": 6.0,
"suffix": "None"
}
}
}
],
"callee": {
@ -448,15 +422,22 @@ description: Result of parsing circular_pattern3d_a_pattern.kcl
"start": 189,
"type": "Identifier"
},
"end": 276,
"end": 277,
"start": 189,
"type": "CallExpression",
"type": "CallExpression"
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": {
"end": 221,
"name": "exampleSketch",
"start": 208,
"type": "Identifier",
"type": "Identifier"
}
},
"start": 180,
"type": "VariableDeclarator"
},
"end": 276,
"end": 277,
"kind": "const",
"start": 180,
"type": "VariableDeclaration",
@ -464,241 +445,213 @@ description: Result of parsing circular_pattern3d_a_pattern.kcl
},
{
"declaration": {
"end": 430,
"end": 432,
"id": {
"end": 284,
"end": 285,
"name": "pattn2",
"start": 278,
"start": 279,
"type": "Identifier"
},
"init": {
"arguments": [
{
"end": 421,
"properties": [
{
"end": 325,
"key": {
"end": 313,
"name": "axis",
"start": 309,
"type": "Identifier"
},
"start": 309,
"type": "ObjectProperty",
"value": {
"elements": [
{
"end": 318,
"raw": "0",
"start": 317,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"end": 321,
"raw": "0",
"start": 320,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"end": 324,
"raw": "1",
"start": 323,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
}
],
"end": 325,
"start": 316,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 353,
"key": {
"end": 335,
"name": "center",
"start": 329,
"type": "Identifier"
},
"start": 329,
"type": "ObjectProperty",
"value": {
"elements": [
{
"argument": {
"end": 342,
"raw": "20",
"start": 340,
"type": "Literal",
"type": "Literal",
"value": {
"value": 20.0,
"suffix": "None"
}
},
"end": 342,
"operator": "-",
"start": 339,
"type": "UnaryExpression",
"type": "UnaryExpression"
},
{
"argument": {
"end": 347,
"raw": "20",
"start": 345,
"type": "Literal",
"type": "Literal",
"value": {
"value": 20.0,
"suffix": "None"
}
},
"end": 347,
"operator": "-",
"start": 344,
"type": "UnaryExpression",
"type": "UnaryExpression"
},
{
"argument": {
"end": 352,
"raw": "20",
"start": 350,
"type": "Literal",
"type": "Literal",
"value": {
"value": 20.0,
"suffix": "None"
}
},
"end": 352,
"operator": "-",
"start": 349,
"type": "UnaryExpression",
"type": "UnaryExpression"
}
],
"end": 353,
"start": 338,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 371,
"key": {
"end": 366,
"name": "instances",
"start": 357,
"type": "Identifier"
},
"start": 357,
"type": "ObjectProperty",
"value": {
"end": 371,
"raw": "41",
"start": 369,
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "axis"
},
"arg": {
"elements": [
{
"end": 328,
"raw": "0",
"start": 327,
"type": "Literal",
"type": "Literal",
"value": {
"value": 41.0,
"value": 0.0,
"suffix": "None"
}
}
},
{
"end": 391,
"key": {
"end": 385,
"name": "arcDegrees",
"start": 375,
"type": "Identifier"
},
"start": 375,
"type": "ObjectProperty",
"value": {
"end": 391,
"raw": "360",
"start": 388,
{
"end": 331,
"raw": "0",
"start": 330,
"type": "Literal",
"type": "Literal",
"value": {
"value": 360.0,
"value": 0.0,
"suffix": "None"
}
},
{
"end": 334,
"raw": "1",
"start": 333,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
}
},
{
"end": 419,
"key": {
"end": 411,
"name": "rotateDuplicates",
"start": 395,
"type": "Identifier"
},
"start": 395,
"type": "ObjectProperty",
"value": {
"end": 419,
"raw": "false",
"start": 414,
"type": "Literal",
"type": "Literal",
"value": false
}
}
],
"start": 305,
"type": "ObjectExpression",
"type": "ObjectExpression"
],
"end": 335,
"start": 326,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 429,
"name": "pattn1",
"start": 423,
"type": "Identifier",
"type": "Identifier"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "center"
},
"arg": {
"elements": [
{
"argument": {
"end": 352,
"raw": "20",
"start": 350,
"type": "Literal",
"type": "Literal",
"value": {
"value": 20.0,
"suffix": "None"
}
},
"end": 352,
"operator": "-",
"start": 349,
"type": "UnaryExpression",
"type": "UnaryExpression"
},
{
"argument": {
"end": 357,
"raw": "20",
"start": 355,
"type": "Literal",
"type": "Literal",
"value": {
"value": 20.0,
"suffix": "None"
}
},
"end": 357,
"operator": "-",
"start": 354,
"type": "UnaryExpression",
"type": "UnaryExpression"
},
{
"argument": {
"end": 362,
"raw": "20",
"start": 360,
"type": "Literal",
"type": "Literal",
"value": {
"value": 20.0,
"suffix": "None"
}
},
"end": 362,
"operator": "-",
"start": 359,
"type": "UnaryExpression",
"type": "UnaryExpression"
}
],
"end": 363,
"start": 348,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "instances"
},
"arg": {
"end": 381,
"raw": "41",
"start": 379,
"type": "Literal",
"type": "Literal",
"value": {
"value": 41.0,
"suffix": "None"
}
}
},
{
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "arcDegrees"
},
"arg": {
"end": 401,
"raw": "360",
"start": 398,
"type": "Literal",
"type": "Literal",
"value": {
"value": 360.0,
"suffix": "None"
}
}
},
{
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "rotateDuplicates"
},
"arg": {
"end": 429,
"raw": "false",
"start": 424,
"type": "Literal",
"type": "Literal",
"value": false
}
}
],
"callee": {
"end": 304,
"end": 305,
"name": "patternCircular3d",
"start": 287,
"start": 288,
"type": "Identifier"
},
"end": 430,
"start": 287,
"type": "CallExpression",
"type": "CallExpression"
"end": 432,
"start": 288,
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": {
"end": 315,
"name": "pattn1",
"start": 309,
"type": "Identifier",
"type": "Identifier"
}
},
"start": 278,
"start": 279,
"type": "VariableDeclarator"
},
"end": 430,
"end": 432,
"kind": "const",
"start": 278,
"start": 279,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"end": 431,
"end": 433,
"nonCodeMeta": {
"nonCodeNodes": {
"0": [
@ -713,8 +666,8 @@ description: Result of parsing circular_pattern3d_a_pattern.kcl
],
"1": [
{
"end": 278,
"start": 276,
"end": 279,
"start": 277,
"type": "NonCodeNode",
"value": {
"type": "newLine"

View File

@ -6,16 +6,18 @@ exampleSketch = startSketchOn('XZ')
|> close(%)
|> extrude(length = 1)
pattn1 = patternLinear3d({
pattn1 = patternLinear3d(
exampleSketch,
axis = [1, 0, 0],
instances = 7,
distance = 6
}, exampleSketch)
distance = 6,
)
pattn2 = patternCircular3d({
pattn2 = patternCircular3d(
pattn1,
axis = [0, 0, 1],
center = [-20, -20, -20],
instances = 41,
arcDegrees = 360,
rotateDuplicates = false
}, pattn1)
rotateDuplicates = false,
)

View File

@ -44,17 +44,24 @@ snapshot_kind: text
},
{
"labeledArgs": {
"data": {
"axis": {
"sourceRange": [
205,
260,
232,
241,
0
]
},
"solid_set": {
"distance": {
"sourceRange": [
262,
275,
273,
274,
0
]
},
"instances": {
"sourceRange": [
257,
258,
0
]
}
@ -62,24 +69,51 @@ snapshot_kind: text
"name": "patternLinear3d",
"sourceRange": [
189,
276,
277,
0
],
"type": "StdLibCall",
"unlabeledArg": null
"unlabeledArg": {
"sourceRange": [
208,
221,
0
]
}
},
{
"labeledArgs": {
"data": {
"arcDegrees": {
"sourceRange": [
305,
421,
398,
401,
0
]
},
"solid_set": {
"axis": {
"sourceRange": [
423,
326,
335,
0
]
},
"center": {
"sourceRange": [
348,
363,
0
]
},
"instances": {
"sourceRange": [
379,
381,
0
]
},
"rotateDuplicates": {
"sourceRange": [
424,
429,
0
]
@ -87,11 +121,17 @@ snapshot_kind: text
},
"name": "patternCircular3d",
"sourceRange": [
287,
430,
288,
432,
0
],
"type": "StdLibCall",
"unlabeledArg": null
"unlabeledArg": {
"sourceRange": [
309,
315,
0
]
}
}
]

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing cube.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing cube_with_error.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing fillet-and-shell.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing fillet-and-shell.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing function_sketch.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing function_sketch_with_position.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Artifact commands helix_simple.kcl
snapshot_kind: text
---
[
{
@ -383,7 +384,7 @@ description: Artifact commands helix_simple.kcl
"cmdId": "[uuid]",
"range": [
151,
242,
257,
0
],
"command": {

View File

@ -5,7 +5,7 @@ flowchart LR
3["Segment<br>[102, 137, 0]"]
end
1["Plane<br>[46, 65, 0]"]
4["Helix<br>[151, 242, 0]"]
4["Helix<br>[151, 257, 0]"]
1 --- 2
2 --- 3
3 <--x 4

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing helix_simple.kcl
snapshot_kind: text
---
{
"Ok": {
@ -171,7 +172,7 @@ description: Result of parsing helix_simple.kcl
},
{
"declaration": {
"end": 242,
"end": 257,
"id": {
"end": 148,
"name": "helixPath",
@ -187,9 +188,9 @@ description: Result of parsing helix_simple.kcl
"name": "angleStart"
},
"arg": {
"end": 171,
"end": 174,
"raw": "0",
"start": 170,
"start": 173,
"type": "Literal",
"type": "Literal",
"value": {
@ -205,9 +206,9 @@ description: Result of parsing helix_simple.kcl
"name": "ccw"
},
"arg": {
"end": 183,
"end": 188,
"raw": "true",
"start": 179,
"start": 184,
"type": "Literal",
"type": "Literal",
"value": true
@ -220,9 +221,9 @@ description: Result of parsing helix_simple.kcl
"name": "revolutions"
},
"arg": {
"end": 200,
"end": 207,
"raw": "5",
"start": 199,
"start": 206,
"type": "Literal",
"type": "Literal",
"value": {
@ -238,9 +239,9 @@ description: Result of parsing helix_simple.kcl
"name": "length"
},
"arg": {
"end": 213,
"end": 222,
"raw": "10",
"start": 211,
"start": 220,
"type": "Literal",
"type": "Literal",
"value": {
@ -256,9 +257,9 @@ description: Result of parsing helix_simple.kcl
"name": "radius"
},
"arg": {
"end": 225,
"end": 236,
"raw": "5",
"start": 224,
"start": 235,
"type": "Literal",
"type": "Literal",
"value": {
@ -274,9 +275,9 @@ description: Result of parsing helix_simple.kcl
"name": "axis"
},
"arg": {
"end": 241,
"end": 254,
"name": "edge001",
"start": 234,
"start": 247,
"type": "Identifier",
"type": "Identifier"
}
@ -288,7 +289,7 @@ description: Result of parsing helix_simple.kcl
"start": 151,
"type": "Identifier"
},
"end": 242,
"end": 257,
"start": 151,
"type": "CallExpressionKw",
"type": "CallExpressionKw",
@ -297,14 +298,14 @@ description: Result of parsing helix_simple.kcl
"start": 139,
"type": "VariableDeclarator"
},
"end": 242,
"end": 257,
"kind": "const",
"start": 139,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"end": 243,
"end": 258,
"nonCodeMeta": {
"nonCodeNodes": {
"0": [

View File

@ -3,4 +3,11 @@ helper001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> line(end = [0, 10], tag = $edge001)
helixPath = helix(angleStart = 0, ccw = true, revolutions = 5, length = 10, radius = 5, axis = edge001)
helixPath = helix(
angleStart = 0,
ccw = true,
revolutions = 5,
length = 10,
radius = 5,
axis = edge001,
)

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Operations executed helix_simple.kcl
snapshot_kind: text
---
[
{
@ -26,43 +27,43 @@ description: Operations executed helix_simple.kcl
"labeledArgs": {
"angleStart": {
"sourceRange": [
170,
171,
173,
174,
0
]
},
"axis": {
"sourceRange": [
234,
241,
247,
254,
0
]
},
"ccw": {
"sourceRange": [
179,
183,
184,
188,
0
]
},
"length": {
"sourceRange": [
211,
213,
220,
222,
0
]
},
"radius": {
"sourceRange": [
224,
225,
235,
236,
0
]
},
"revolutions": {
"sourceRange": [
199,
200,
206,
207,
0
]
}
@ -70,7 +71,7 @@ description: Operations executed helix_simple.kcl
"name": "helix",
"sourceRange": [
151,
242,
257,
0
],
"type": "StdLibCall",

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing helix_simple.kcl
snapshot_kind: text
---
{
"environments": [
@ -86,7 +87,7 @@ description: Program memory after executing helix_simple.kcl
{
"sourceRange": [
151,
242,
257,
0
]
}

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing import_cycle1.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing import_function_not_sketch.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing import_function_not_sketch.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Program memory after executing import_side_effect.kcl
snapshot_kind: text
---
{
"environments": [

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing import_whole.kcl
snapshot_kind: text
---
{
"Ok": {

View File

@ -631,7 +631,7 @@ snapshot_kind: text
"cmdId": "[uuid]",
"range": [
189,
276,
277,
0
],
"command": {
@ -819,8 +819,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {
@ -1008,8 +1008,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {
@ -1197,8 +1197,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {
@ -1386,8 +1386,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {
@ -1575,8 +1575,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {
@ -1764,8 +1764,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {
@ -1953,8 +1953,8 @@ snapshot_kind: text
{
"cmdId": "[uuid]",
"range": [
287,
367,
288,
369,
0
],
"command": {

View File

@ -1,6 +1,7 @@
---
source: kcl/src/simulation_tests.rs
description: Result of parsing linear_pattern3d_a_pattern.kcl
snapshot_kind: text
---
{
"Ok": {
@ -321,7 +322,7 @@ description: Result of parsing linear_pattern3d_a_pattern.kcl
},
{
"declaration": {
"end": 276,
"end": 277,
"id": {
"end": 186,
"name": "pattn1",
@ -331,115 +332,88 @@ description: Result of parsing linear_pattern3d_a_pattern.kcl
"init": {
"arguments": [
{
"end": 260,
"properties": [
{
"end": 225,
"key": {
"end": 213,
"name": "axis",
"start": 209,
"type": "Identifier"
},
"start": 209,
"type": "ObjectProperty",
"value": {
"elements": [
{
"end": 218,
"raw": "1",
"start": 217,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
},
{
"end": 221,
"raw": "0",
"start": 220,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"end": 224,
"raw": "0",
"start": 223,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
}
],
"end": 225,
"start": 216,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 242,
"key": {
"end": 238,
"name": "instances",
"start": 229,
"type": "Identifier"
},
"start": 229,
"type": "ObjectProperty",
"value": {
"end": 242,
"raw": "7",
"start": 241,
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "axis"
},
"arg": {
"elements": [
{
"end": 234,
"raw": "1",
"start": 233,
"type": "Literal",
"type": "Literal",
"value": {
"value": 7.0,
"value": 1.0,
"suffix": "None"
}
}
},
{
"end": 258,
"key": {
"end": 254,
"name": "distance",
"start": 246,
"type": "Identifier"
},
"start": 246,
"type": "ObjectProperty",
"value": {
"end": 258,
"raw": "6",
"start": 257,
{
"end": 237,
"raw": "0",
"start": 236,
"type": "Literal",
"type": "Literal",
"value": {
"value": 6.0,
"value": 0.0,
"suffix": "None"
}
},
{
"end": 240,
"raw": "0",
"start": 239,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
}
}
],
"start": 205,
"type": "ObjectExpression",
"type": "ObjectExpression"
],
"end": 241,
"start": 232,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 275,
"name": "exampleSketch",
"start": 262,
"type": "Identifier",
"type": "Identifier"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "instances"
},
"arg": {
"end": 258,
"raw": "7",
"start": 257,
"type": "Literal",
"type": "Literal",
"value": {
"value": 7.0,
"suffix": "None"
}
}
},
{
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "distance"
},
"arg": {
"end": 274,
"raw": "6",
"start": 273,
"type": "Literal",
"type": "Literal",
"value": {
"value": 6.0,
"suffix": "None"
}
}
}
],
"callee": {
@ -448,15 +422,22 @@ description: Result of parsing linear_pattern3d_a_pattern.kcl
"start": 189,
"type": "Identifier"
},
"end": 276,
"end": 277,
"start": 189,
"type": "CallExpression",
"type": "CallExpression"
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": {
"end": 221,
"name": "exampleSketch",
"start": 208,
"type": "Identifier",
"type": "Identifier"
}
},
"start": 180,
"type": "VariableDeclarator"
},
"end": 276,
"end": 277,
"kind": "const",
"start": 180,
"type": "VariableDeclaration",
@ -464,84 +445,49 @@ description: Result of parsing linear_pattern3d_a_pattern.kcl
},
{
"declaration": {
"end": 367,
"end": 369,
"id": {
"end": 284,
"end": 285,
"name": "pattn2",
"start": 278,
"start": 279,
"type": "Identifier"
},
"init": {
"arguments": [
{
"end": 358,
"properties": [
{
"end": 323,
"key": {
"end": 311,
"name": "axis",
"start": 307,
"type": "Identifier"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "axis"
},
"arg": {
"elements": [
{
"end": 326,
"raw": "0",
"start": 325,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
"start": 307,
"type": "ObjectProperty",
"value": {
"elements": [
{
"end": 316,
"raw": "0",
"start": 315,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"end": 319,
"raw": "0",
"start": 318,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
{
"end": 322,
"raw": "1",
"start": 321,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
}
],
"end": 323,
"start": 314,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 339,
"key": {
"end": 335,
"name": "distance",
"start": 327,
"type": "Identifier"
{
"end": 329,
"raw": "0",
"start": 328,
"type": "Literal",
"type": "Literal",
"value": {
"value": 0.0,
"suffix": "None"
}
},
"start": 327,
"type": "ObjectProperty",
"value": {
"end": 339,
{
"end": 332,
"raw": "1",
"start": 338,
"start": 331,
"type": "Literal",
"type": "Literal",
"value": {
@ -549,64 +495,79 @@ description: Result of parsing linear_pattern3d_a_pattern.kcl
"suffix": "None"
}
}
},
{
"end": 356,
"key": {
"end": 352,
"name": "instances",
"start": 343,
"type": "Identifier"
},
"start": 343,
"type": "ObjectProperty",
"value": {
"end": 356,
"raw": "7",
"start": 355,
"type": "Literal",
"type": "Literal",
"value": {
"value": 7.0,
"suffix": "None"
}
}
}
],
"start": 303,
"type": "ObjectExpression",
"type": "ObjectExpression"
],
"end": 333,
"start": 324,
"type": "ArrayExpression",
"type": "ArrayExpression"
}
},
{
"end": 366,
"name": "pattn1",
"start": 360,
"type": "Identifier",
"type": "Identifier"
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "distance"
},
"arg": {
"end": 349,
"raw": "1",
"start": 348,
"type": "Literal",
"type": "Literal",
"value": {
"value": 1.0,
"suffix": "None"
}
}
},
{
"type": "LabeledArg",
"label": {
"type": "Identifier",
"name": "instances"
},
"arg": {
"end": 366,
"raw": "7",
"start": 365,
"type": "Literal",
"type": "Literal",
"value": {
"value": 7.0,
"suffix": "None"
}
}
}
],
"callee": {
"end": 302,
"end": 303,
"name": "patternLinear3d",
"start": 287,
"start": 288,
"type": "Identifier"
},
"end": 367,
"start": 287,
"type": "CallExpression",
"type": "CallExpression"
"end": 369,
"start": 288,
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": {
"end": 313,
"name": "pattn1",
"start": 307,
"type": "Identifier",
"type": "Identifier"
}
},
"start": 278,
"start": 279,
"type": "VariableDeclarator"
},
"end": 367,
"end": 369,
"kind": "const",
"start": 278,
"start": 279,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"end": 368,
"end": 370,
"nonCodeMeta": {
"nonCodeNodes": {
"0": [
@ -621,8 +582,8 @@ description: Result of parsing linear_pattern3d_a_pattern.kcl
],
"1": [
{
"end": 278,
"start": 276,
"end": 279,
"start": 277,
"type": "NonCodeNode",
"value": {
"type": "newLine"

View File

@ -6,14 +6,16 @@ exampleSketch = startSketchOn('XZ')
|> close(%)
|> extrude(length = 1)
pattn1 = patternLinear3d({
pattn1 = patternLinear3d(
exampleSketch,
axis = [1, 0, 0],
instances = 7,
distance = 6
}, exampleSketch)
distance = 6,
)
pattn2 = patternLinear3d({
pattn2 = patternLinear3d(
pattn1,
axis = [0, 0, 1],
distance = 1,
instances = 7
}, pattn1)
instances = 7,
)

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