Compare commits

...

6 Commits

Author SHA1 Message Date
bdc9b7267b Update src/lang/std/sketch.ts
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-08-28 11:05:13 -05:00
b54a17a4fa Merge main 2024-08-28 11:05:11 -05:00
956f00c5a1 Migrate code within JS 2024-08-28 10:56:43 -05:00
c585efa024 Update docs 2024-08-28 10:54:07 -05:00
a37d395b76 Fix up tests 2024-08-28 10:54:06 -05:00
548eac57af Add 'relative: bool' to tanArcTo, remove 'to' mode from tanArc 2024-08-28 10:52:53 -05:00
37 changed files with 7975 additions and 136 deletions

View File

@ -33,8 +33,18 @@ jobs:
rust: rust:
- 'src/wasm-lib/**' - 'src/wasm-lib/**'
<<<<<<< HEAD
playwright-chrome: playwright-chrome:
timeout-minutes: ${{ matrix.os == 'macos-14' && 60 || 40 }} timeout-minutes: ${{ matrix.os == 'macos-14' && 60 || 40 }}
||||||| parent of 1f27643b (Merge main)
playwright-ubuntu:
timeout-minutes: 30
runs-on: ubuntu-latest-8-cores
=======
playwright-ubuntu:
timeout-minutes: 30
runs-on: ubuntu-latest
>>>>>>> 1f27643b (Merge main)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View File

@ -217149,8 +217149,8 @@
}, },
{ {
"name": "tangentialArc", "name": "tangentialArc",
"summary": "Starting at the current sketch's origin, draw a curved line segment along", "summary": "Draw a curved line segment along some part of an imaginary circle of the specified radius.",
"description": "some part of an imaginary circle of the specified radius.\nThe arc is constructed such that the last line segment is placed tangent to the imaginary circle of the specified radius. The resulting arc is the segment of the imaginary circle from that tangent point for 'offset' degrees along the imaginary circle.", "description": "If `relative` is true, the curve starts at the end of the previous path segment (i.e. the location of the \"pen\" which draws these lines). If `relative` is false, starts from the current sketch's origin.\nThe arc is constructed such that the last line segment is placed tangent to the imaginary circle of the specified radius. The resulting arc is the segment of the imaginary circle from that tangent point for 'offset' degrees along the imaginary circle.",
"tags": [], "tags": [],
"args": [ "args": [
{ {
@ -217177,16 +217177,6 @@
"format": "double" "format": "double"
} }
} }
},
{
"description": "A point where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.",
"type": "array",
"items": {
"type": "number",
"format": "double"
},
"maxItems": 2,
"minItems": 2
} }
] ]
}, },
@ -223895,6 +223885,14 @@
}, },
"required": true "required": true
}, },
{
"name": "relative",
"type": "bool",
"schema": {
"type": "boolean"
},
"required": true
},
{ {
"name": "sketch_group", "name": "sketch_group",
"type": "SketchGroup", "type": "SketchGroup",
@ -230575,7 +230573,7 @@
"unpublished": false, "unpublished": false,
"deprecated": false, "deprecated": false,
"examples": [ "examples": [
"const exampleSketch = startSketchOn('XZ')\n |> startProfileAt([0, 0], %)\n |> angledLine({ angle: 60, length: 10 }, %)\n |> tangentialArcTo([15, 15], %)\n |> line([10, -15], %)\n |> close(%)\n\nconst example = extrude(10, exampleSketch)" "const exampleSketch = startSketchOn('XZ')\n |> startProfileAt([0, 0], %)\n |> angledLine({ angle: 60, length: 10 }, %)\n |> tangentialArcTo([15, 15], false, %)\n |> line([10, -15], %)\n |> close(%)\n\nconst example = extrude(10, exampleSketch)"
] ]
}, },
{ {

View File

@ -1,12 +1,12 @@
--- ---
title: "tangentialArc" title: "tangentialArc"
excerpt: "Starting at the current sketch's origin, draw a curved line segment along" excerpt: "Draw a curved line segment along some part of an imaginary circle of the specified radius."
layout: manual layout: manual
--- ---
Starting at the current sketch's origin, draw a curved line segment along Draw a curved line segment along some part of an imaginary circle of the specified radius.
some part of an imaginary circle of the specified radius. If `relative` is true, the curve starts at the end of the previous path segment (i.e. the location of the "pen" which draws these lines). If `relative` is false, starts from the current sketch's origin.
The arc is constructed such that the last line segment is placed tangent to the imaginary circle of the specified radius. The resulting arc is the segment of the imaginary circle from that tangent point for 'offset' degrees along the imaginary circle. The arc is constructed such that the last line segment is placed tangent to the imaginary circle of the specified radius. The resulting arc is the segment of the imaginary circle from that tangent point for 'offset' degrees along the imaginary circle.
```js ```js
@ -37,8 +37,7 @@ const example = extrude(10, exampleSketch)
offset: number, offset: number,
// Radius of the arc. Not to be confused with Raiders of the Lost Ark. // Radius of the arc. Not to be confused with Raiders of the Lost Ark.
radius: number, radius: number,
} | }
[number, number]
``` ```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED) * `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js ```js

View File

@ -9,7 +9,7 @@ Starting at the current sketch's origin, draw a curved line segment along
some part of an imaginary circle until it reaches the desired (x, y) coordinates. some part of an imaginary circle until it reaches the desired (x, y) coordinates.
```js ```js
tangentialArcTo(to: [number], sketch_group: SketchGroup, tag?: TagDeclarator) -> SketchGroup tangentialArcTo(to: [number], relative: bool, sketch_group: SketchGroup, tag?: TagDeclarator) -> SketchGroup
``` ```
### Examples ### Examples
@ -18,7 +18,7 @@ tangentialArcTo(to: [number], sketch_group: SketchGroup, tag?: TagDeclarator) ->
const exampleSketch = startSketchOn('XZ') const exampleSketch = startSketchOn('XZ')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine({ angle: 60, length: 10 }, %) |> angledLine({ angle: 60, length: 10 }, %)
|> tangentialArcTo([15, 15], %) |> tangentialArcTo([15, 15], false, %)
|> line([10, -15], %) |> line([10, -15], %)
|> close(%) |> close(%)
@ -30,6 +30,7 @@ const example = extrude(10, exampleSketch)
### Arguments ### Arguments
* `to`: `[number]` (REQUIRED) * `to`: `[number]` (REQUIRED)
* `relative`: `bool` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED) * `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js ```js
{ {

View File

@ -763,7 +763,7 @@ test.describe('Editor tests', () => {
`const sketch001 = startSketchOn('XZ') `const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> close(%)` |> close(%)`
) )
}) })
@ -812,7 +812,7 @@ test.describe('Editor tests', () => {
// expect the code to have changed // expect the code to have changed
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`const sketch001 = startSketchOn('XZ') |> startProfileAt([4.61, -14.01], %) |> line([12.73, -0.09], %) |> tangentialArcTo([24.95, -5.38], %) |> close(%)const extrude001 = extrude(5, sketch001)` `const sketch001 = startSketchOn('XZ') |> startProfileAt([4.61, -14.01], %) |> line([12.73, -0.09], %) |> tangentialArcTo([24.95, -5.38], false, %) |> close(%)const extrude001 = extrude(5, sketch001)`
) )
// Now hit undo // Now hit undo
@ -825,7 +825,7 @@ test.describe('Editor tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> close(%)`) |> close(%)`)
}) })
@ -837,7 +837,7 @@ test.describe('Editor tests', () => {
`const sketch001 = startSketchOn('XZ') `const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> close(%) |> close(%)
|> extrude(5, %)` |> extrude(5, %)`
) )
@ -928,7 +928,7 @@ test.describe('Editor tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %) |> line([15.39, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %) |> tangentialArcTo([27.6, -3.05], false, %)
|> close(%) |> close(%)
|> extrude(5, %) |> extrude(5, %)
`) `)
@ -942,7 +942,7 @@ test.describe('Editor tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %) |> line([15.39, -2.78], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], false, %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
@ -955,7 +955,7 @@ test.describe('Editor tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([7.12, -12.68], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], false, %)
|> close(%) |> close(%)
|> extrude(5, %) |> extrude(5, %)
`) `)
@ -970,7 +970,7 @@ test.describe('Editor tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], false, %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
}) })

View File

@ -61,7 +61,7 @@ test.describe('Sketch tests', () => {
const part002 = startSketchOn('-XZ') const part002 = startSketchOn('-XZ')
${startProfileAt3} ${startProfileAt3}
|> xLine(width / 4, %) |> xLine(width / 4, %)
|> tangentialArcTo([width / 2, 0], %) |> tangentialArcTo([width / 2, 0], false, %)
|> xLine(-width / 4 + wireRadius, %) |> xLine(-width / 4 + wireRadius, %)
|> yLine(wireOffset, %) |> yLine(wireOffset, %)
|> arc({ |> arc({
@ -115,7 +115,7 @@ test.describe('Sketch tests', () => {
`const sketch001 = startSketchOn('XZ') `const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %)` |> tangentialArcTo([24.95, -5.38], false, %)`
) )
}) })
@ -125,7 +125,7 @@ test.describe('Sketch tests', () => {
await expect(async () => { await expect(async () => {
await page.mouse.click(700, 200) await page.mouse.click(700, 200)
await page.getByText('tangentialArcTo([24.95, -5.38], %)').click() await page.getByText('tangentialArcTo([24.95, -5.38], false, %)').click()
await expect( await expect(
page.getByRole('button', { name: 'Edit Sketch' }) page.getByRole('button', { name: 'Edit Sketch' })
).toBeEnabled({ timeout: 1000 }) ).toBeEnabled({ timeout: 1000 })
@ -134,7 +134,7 @@ test.describe('Sketch tests', () => {
await page.waitForTimeout(600) // wait for animation await page.waitForTimeout(600) // wait for animation
await page.getByText('tangentialArcTo([24.95, -5.38], %)').click() await page.getByText('tangentialArcTo([24.95, -5.38], false, %)').click()
await page.keyboard.press('End') await page.keyboard.press('End')
await page.keyboard.down('Shift') await page.keyboard.down('Shift')
await page.keyboard.press('ArrowUp') await page.keyboard.press('ArrowUp')
@ -193,7 +193,7 @@ test.describe('Sketch tests', () => {
`const sketch001 = startSketchOn('XZ') `const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> close(%)` |> close(%)`
) )
}) })
@ -235,7 +235,7 @@ test.describe('Sketch tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> close(%)`) |> close(%)`)
} else { } else {
// Ensure we don't see the code. // Ensure we don't see the code.
@ -312,7 +312,7 @@ test.describe('Sketch tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([6.44, -12.07], %) |> startProfileAt([6.44, -12.07], %)
|> line([14.72, 1.97], %) |> line([14.72, 1.97], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> line([1.97, 2.06], %) |> line([1.97, 2.06], %)
|> close(%)`) |> close(%)`)
} }
@ -354,7 +354,7 @@ test.describe('Sketch tests', () => {
`const sketch001 = startSketchOn('XZ') `const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], false, %)
|> close(%) |> close(%)
|> extrude(5, %)` |> extrude(5, %)`
) )
@ -441,7 +441,7 @@ test.describe('Sketch tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %) |> line([15.39, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %) |> tangentialArcTo([27.6, -3.05], false, %)
|> close(%) |> close(%)
|> extrude(5, %) |> extrude(5, %)
`) `)
@ -457,7 +457,7 @@ test.describe('Sketch tests', () => {
`const sketch001 = startSketchOn('XZ') `const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> close(%) |> close(%)
|> revolve({ axis: "X",}, %)` |> revolve({ axis: "X",}, %)`
) )
@ -543,7 +543,7 @@ test.describe('Sketch tests', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([6.44, -12.07], %) |> startProfileAt([6.44, -12.07], %)
|> line([14.72, 1.97], %) |> line([14.72, 1.97], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], false, %)
|> line([1.97, 2.06], %) |> line([1.97, 2.06], %)
|> close(%) |> close(%)
|> revolve({ axis: "X" }, %)`) |> revolve({ axis: "X" }, %)`)

View File

@ -594,7 +594,7 @@ test.describe(
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20) await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
code += ` code += `
|> tangentialArcTo([21.7, -2.44], %)` |> tangentialArcTo([21.7, -2.44], false, %)`
await expect(u.codeLocator).toHaveText(code) await expect(u.codeLocator).toHaveText(code)
// click tangential arc tool again to unequip it // click tangential arc tool again to unequip it
@ -697,7 +697,7 @@ test.describe(
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20) await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
code += ` code += `
|> tangentialArcTo([551.2, -62.01], %)` |> tangentialArcTo([551.2, -62.01], false, %)`
await expect(u.codeLocator).toHaveText(code) await expect(u.codeLocator).toHaveText(code)
await page await page

View File

@ -84,7 +84,7 @@ export const TEST_CODE_GIZMO = `const part001 = startSketchOn('XZ')
intersectTag: a, intersectTag: a,
offset: 0 offset: 0
}, %) }, %)
|> tangentialArcTo([13.14 + 0, 13.14], %) |> tangentialArcTo([13.14 + 0, 13.14], false, %)
|> close(%) |> close(%)
|> extrude(5 + 7, %) |> extrude(5 + 7, %)
` `

View File

@ -314,6 +314,7 @@ export function normaliseKclNumbers(code: string, ignoreZero = true): string {
return replaceNumbers(code) return replaceNumbers(code)
} }
<<<<<<< HEAD
export async function getUtils(page: Page, test_?: typeof test) { export async function getUtils(page: Page, test_?: typeof test) {
if (!test) { if (!test) {
console.warn( console.warn(
@ -321,6 +322,11 @@ export async function getUtils(page: Page, test_?: typeof test) {
) )
} }
||||||| parent of 1f27643b (Merge main)
export async function getUtils(page: Page) {
=======
export async function getUtils(page: Page) {
>>>>>>> 1f27643b (Merge main)
// Chrome devtools protocol session only works in Chromium // Chrome devtools protocol session only works in Chromium
const browserType = page.context().browser()?.browserType().name() const browserType = page.context().browser()?.browserType().name()
const cdpSession = const cdpSession =

View File

@ -200,7 +200,7 @@ test.describe('Testing segment overlays', () => {
intersectTag: a, intersectTag: a,
offset: 9 offset: 9
}, %) }, %)
|> tangentialArcTo([5 + 3.14 + 13, 20 + 3.14], %) |> tangentialArcTo([5 + 3.14 + 13, 20 + 3.14], false, %)
` `
) )
}) })
@ -438,7 +438,7 @@ const part001 = startSketchOn('XZ')
intersectTag: a, intersectTag: a,
offset: 9 offset: 9
}, %) }, %)
|> tangentialArcTo([3.14 + 13, 3.14], %) |> tangentialArcTo([3.14 + 13, 3.14], false, %)
` `
) )
localStorage.setItem('disableAxis', 'true') localStorage.setItem('disableAxis', 'true')
@ -566,7 +566,7 @@ const part001 = startSketchOn('XZ')
intersectTag: a, intersectTag: a,
offset: 9 offset: 9
}, %) }, %)
|> tangentialArcTo([3.14 + 13, 1.14], %) |> tangentialArcTo([3.14 + 13, 1.14], false, %)
` `
) )
localStorage.setItem('disableAxis', 'true') localStorage.setItem('disableAxis', 'true')
@ -722,7 +722,7 @@ const part001 = startSketchOn('XZ')
intersectTag: a, intersectTag: a,
offset: 9 offset: 9
}, %) }, %)
|> tangentialArcTo([3.14 + 13, -3.14], %) |> tangentialArcTo([3.14 + 13, -3.14], false, %)
` `
) )
localStorage.setItem('disableAxis', 'true') localStorage.setItem('disableAxis', 'true')
@ -755,9 +755,10 @@ const part001 = startSketchOn('XZ')
await clickConstrained({ await clickConstrained({
hoverPos: { x: tangentialArcTo.x, y: tangentialArcTo.y }, hoverPos: { x: tangentialArcTo.x, y: tangentialArcTo.y },
constraintType: 'xAbsolute', constraintType: 'xAbsolute',
expectBeforeUnconstrained: 'tangentialArcTo([3.14 + 13, -3.14], %)', expectBeforeUnconstrained:
expectAfterUnconstrained: 'tangentialArcTo([16.14, -3.14], %)', 'tangentialArcTo([3.14 + 13, -3.14], false, %)',
expectFinal: 'tangentialArcTo([xAbs001, -3.14], %)', expectAfterUnconstrained: 'tangentialArcTo([16.14, -3.14], false, %)',
expectFinal: 'tangentialArcTo([xAbs001, -3.14], false, %)',
ang: ang + 180, ang: ang + 180,
steps: 6, steps: 6,
locator: '[data-overlay-toolbar-index="12"]', locator: '[data-overlay-toolbar-index="12"]',
@ -766,9 +767,11 @@ const part001 = startSketchOn('XZ')
await clickUnconstrained({ await clickUnconstrained({
hoverPos: { x: tangentialArcTo.x, y: tangentialArcTo.y }, hoverPos: { x: tangentialArcTo.x, y: tangentialArcTo.y },
constraintType: 'yAbsolute', constraintType: 'yAbsolute',
expectBeforeUnconstrained: 'tangentialArcTo([xAbs001, -3.14], %)', expectBeforeUnconstrained:
expectAfterUnconstrained: 'tangentialArcTo([xAbs001, yAbs001], %)', 'tangentialArcTo([xAbs001, -3.14], false, %)',
expectFinal: 'tangentialArcTo([xAbs001, -3.14], %)', expectAfterUnconstrained:
'tangentialArcTo([xAbs001, yAbs001], false, %)',
expectFinal: 'tangentialArcTo([xAbs001, -3.14], false, %)',
ang: ang + 180, ang: ang + 180,
steps: 10, steps: 10,
locator: '[data-overlay-toolbar-index="12"]', locator: '[data-overlay-toolbar-index="12"]',
@ -835,7 +838,7 @@ const part001 = startSketchOn('XZ')
intersectTag: a, intersectTag: a,
offset: 9 offset: 9
}, %) }, %)
|> tangentialArcTo([3.14 + 13, 1.14], %) |> tangentialArcTo([3.14 + 13, 1.14], false, %)
` `
) )
localStorage.setItem('disableAxis', 'true') localStorage.setItem('disableAxis', 'true')
@ -866,7 +869,7 @@ const part001 = startSketchOn('XZ')
let ang = await u.getAngle(`[data-overlay-index="${12}"]`) let ang = await u.getAngle(`[data-overlay-index="${12}"]`)
await deleteSegmentSequence({ await deleteSegmentSequence({
hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y }, hoverPos: { x: segmentToDelete.x, y: segmentToDelete.y },
codeToBeDeleted: 'tangentialArcTo([3.14 + 13, 1.14], %)', codeToBeDeleted: 'tangentialArcTo([3.14 + 13, 1.14], false, %)',
stdLibFnName: 'tangentialArcTo', stdLibFnName: 'tangentialArcTo',
ang: ang + 180, ang: ang + 180,
steps: 6, steps: 6,

View File

@ -479,7 +479,7 @@ const sketch002 = startSketchOn(launderExtrudeThroughVar, seg02)
intersectTag: a, intersectTag: a,
offset: 0 offset: 0
}, %) }, %)
|> tangentialArcTo([13.14 + 0, 13.14], %) |> tangentialArcTo([13.14 + 0, 13.14], false, %)
|> close(%) |> close(%)
|> extrude(5 + 7, %) |> extrude(5 + 7, %)
` `
@ -683,7 +683,7 @@ const extrude001 = extrude(10, sketch001)`
}, },
{ {
pos: [1107, 161], pos: [1107, 161],
expectedCode: 'tangentialArcTo([167.95, -28.85], %)', expectedCode: 'tangentialArcTo([167.95, -28.85], false, %)',
}, },
] as const ] as const
await page.addInitScript( await page.addInitScript(

View File

@ -77,7 +77,17 @@ test.describe('Testing settings', () => {
exact: true, exact: true,
}) })
const inputLocator = page.locator('input[name="modeling-showDebugPanel"]') const inputLocator = page.locator('input[name="modeling-showDebugPanel"]')
<<<<<<< HEAD
||||||| parent of 1f27643b (Merge main)
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
=======
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
// Open the settings modal with the browser keyboard shortcut // Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('ControlOrMeta+Shift+,') await page.keyboard.press('ControlOrMeta+Shift+,')
@ -128,7 +138,58 @@ test.describe('Testing settings', () => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await u.waitForAuthSkipAppStart()
||||||| parent of 1f27643b (Merge main)
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('dark')
// Roll back to default "system" theme
await page
.getByText(
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
.hover()
await page
.getByRole('button', {
name: 'Roll back theme',
})
.click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
})
test('Project settings can be opened with keybinding from the editor', async ({
page,
}) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })
=======
await expect(headingLocator).toBeVisible()
await page.locator('#showDebugPanel').getByText('OffOn').click()
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
await test.step('Open keybindings settings', async () => { await test.step('Open keybindings settings', async () => {
// Open the settings modal with the browser keyboard shortcut // Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('ControlOrMeta+Shift+,') await page.keyboard.press('ControlOrMeta+Shift+,')
@ -141,7 +202,31 @@ test.describe('Testing settings', () => {
// Go to the hotkey for Command Palette. // Go to the hotkey for Command Palette.
const commandPalette = page.getByText('Toggle Command Palette') const commandPalette = page.getByText('Toggle Command Palette')
await commandPalette.scrollIntoViewIfNeeded() await commandPalette.scrollIntoViewIfNeeded()
||||||| parent of 1f27643b (Merge main)
// Put the cursor in the editor
await page.locator('.cm-content').click()
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
=======
// Close it and open again with keyboard shortcut, while KCL editor is focused
// Put the cursor in the editor
await test.step('Open settings with keyboard shortcut', async () => {
await page.getByTestId('settings-close-button').click()
await page.locator('.cm-content').click()
await page.keyboard.press('Meta+Shift+,')
await expect(headingLocator).toBeVisible()
})
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
// The heading is above it and should be in view now. // The heading is above it and should be in view now.
const commandPaletteHeading = page.getByRole('heading', { const commandPaletteHeading = page.getByRole('heading', {
name: 'Command Palette', name: 'Command Palette',
@ -150,6 +235,63 @@ test.describe('Testing settings', () => {
const hotkey = commandPaletteHeading.locator('+ div kbd') const hotkey = commandPaletteHeading.locator('+ div kbd')
const text = process.platform === 'darwin' ? 'Command+K' : 'Control+K' const text = process.platform === 'darwin' ? 'Command+K' : 'Control+K'
await expect(hotkey).toHaveText(text) await expect(hotkey).toHaveText(text)
||||||| parent of 1f27643b (Merge main)
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('dark')
// Roll back to default "system" theme
await page
.getByText(
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
.hover()
await page
.getByRole('button', {
name: 'Roll back theme',
})
.click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
=======
// Verify the toast appeared
await expect(
page.getByText(`Set show debug panel to "false" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(paneButtonLocator).not.toBeVisible()
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(inputLocator).toBeChecked()
// Roll back to default of "off"
await await page
.getByText('show debug panelRoll back show debug panelRoll back to match')
.hover()
await page
.getByRole('button', {
name: 'Roll back show debug panel',
})
.click()
await expect(inputLocator).not.toBeChecked()
// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(
page.locator('input[name="modeling-showDebugPanel"]')
).not.toBeChecked()
>>>>>>> 1f27643b (Merge main)
}) })
test('Project and user settings can be reset', async ({ page }) => { test('Project and user settings can be reset', async ({ page }) => {
@ -186,6 +328,7 @@ test.describe('Testing settings', () => {
// Set project-level value to 50 // Set project-level value to 50
await themeColorSetting.fill(settingValues.project) await themeColorSetting.fill(settingValues.project)
<<<<<<< HEAD
// Set user-level value to 120 // Set user-level value to 120
await userSettingsTab.click() await userSettingsTab.click()
@ -375,7 +518,14 @@ test.describe('Testing settings', () => {
await page await page
.getByRole('button', { name: 'Start Sketch' }) .getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' }) .waitFor({ state: 'visible' })
||||||| parent of 1f27643b (Merge main)
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
=======
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
const userSettingsTab = page.getByRole('radio', { name: 'User' }) const userSettingsTab = page.getByRole('radio', { name: 'User' })
// Open the settings modal with lower-right button // Open the settings modal with lower-right button
@ -383,13 +533,39 @@ test.describe('Testing settings', () => {
await expect( await expect(
page.getByRole('heading', { name: 'Settings', exact: true }) page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible() ).toBeVisible()
||||||| parent of 1f27643b (Merge main)
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
=======
// Set user-level value to 120
await userSettingsTab.click()
await themeColorSetting.fill(settingValues.user)
await projectSettingsTab.click()
})
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
const resetButton = page.getByRole('button', { const resetButton = page.getByRole('button', {
name: 'Restore default settings', name: 'Restore default settings',
}) })
// Default unit should be mm // Default unit should be mm
await resetButton.click() await resetButton.click()
||||||| parent of 1f27643b (Merge main)
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
=======
await test.step('Reset project settings', async () => {
// Click the reset settings button.
await resetButton.click()
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
await test.step('Change modeling default unit within project tab', async () => { await test.step('Change modeling default unit within project tab', async () => {
const changeUnitOfMeasureInProjectTab = async (unitOfMeasure: string) => { const changeUnitOfMeasureInProjectTab = async (unitOfMeasure: string) => {
await test.step(`Set modeling default unit to ${unitOfMeasure}`, async () => { await test.step(`Set modeling default unit to ${unitOfMeasure}`, async () => {
@ -409,7 +585,15 @@ test.describe('Testing settings', () => {
await changeUnitOfMeasureInProjectTab('cm') await changeUnitOfMeasureInProjectTab('cm')
await changeUnitOfMeasureInProjectTab('m') await changeUnitOfMeasureInProjectTab('m')
}) })
||||||| parent of 1f27643b (Merge main)
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
=======
// Verify it is now set to the inherited user value
await expect(themeColorSetting).toHaveValue(settingValues.default)
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
// Go to the user tab // Go to the user tab
await userSettingsTab.click() await userSettingsTab.click()
await test.step('Change modeling default unit within user tab', async () => { await test.step('Change modeling default unit within user tab', async () => {
@ -431,11 +615,33 @@ test.describe('Testing settings', () => {
await changeUnitOfMeasureInUserTab('cm') await changeUnitOfMeasureInUserTab('cm')
await changeUnitOfMeasureInUserTab('m') await changeUnitOfMeasureInUserTab('m')
}) })
||||||| parent of 1f27643b (Merge main)
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
=======
// Check that the user setting also rolled back
await userSettingsTab.click()
await expect(themeColorSetting).toHaveValue(settingValues.default)
await projectSettingsTab.click()
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
// Close settings // Close settings
const settingsCloseButton = page.getByTestId('settings-close-button') const settingsCloseButton = page.getByTestId('settings-close-button')
await settingsCloseButton.click() await settingsCloseButton.click()
||||||| parent of 1f27643b (Merge main)
// Set the user theme to light.
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
=======
// Set project-level value to 50 again to test the user-level reset
await themeColorSetting.fill(settingValues.project)
await userSettingsTab.click()
})
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
await test.step('Change modeling default unit within command bar', async () => { await test.step('Change modeling default unit within command bar', async () => {
const commands = page.getByRole('button', { name: 'Commands' }) const commands = page.getByRole('button', { name: 'Commands' })
const changeUnitOfMeasureInCommandBar = async (unitOfMeasure: string) => { const changeUnitOfMeasureInCommandBar = async (unitOfMeasure: string) => {
@ -445,13 +651,36 @@ test.describe('Testing settings', () => {
'Settings · modeling · default unit' 'Settings · modeling · default unit'
) )
await settingsModelingDefaultUnitCommand.click() await settingsModelingDefaultUnitCommand.click()
||||||| parent of 1f27643b (Merge main)
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" as a user default`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
=======
await test.step('Reset user settings', async () => {
// Change the setting and click the reset settings button.
await themeColorSetting.fill(settingValues.user)
await resetButton.click()
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
const commandOption = page.getByRole('option', { const commandOption = page.getByRole('option', {
name: unitOfMeasure, name: unitOfMeasure,
exact: true, exact: true,
}) })
await commandOption.click() await commandOption.click()
||||||| parent of 1f27643b (Merge main)
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
=======
// Verify it is now set to the default value
await expect(themeColorSetting).toHaveValue(settingValues.default)
>>>>>>> 1f27643b (Merge main)
<<<<<<< HEAD
const toastMessage = page.getByText( const toastMessage = page.getByText(
`Set default unit to "${unitOfMeasure}" for this project` `Set default unit to "${unitOfMeasure}" for this project`
) )
@ -491,6 +720,25 @@ test.describe('Testing settings', () => {
await changeUnitOfMeasureInGizmo('mm', 'Millimeters') await changeUnitOfMeasureInGizmo('mm', 'Millimeters')
await changeUnitOfMeasureInGizmo('cm', 'Centimeters') await changeUnitOfMeasureInGizmo('cm', 'Centimeters')
await changeUnitOfMeasureInGizmo('m', 'Meters') await changeUnitOfMeasureInGizmo('m', 'Meters')
||||||| parent of 1f27643b (Merge main)
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
=======
// Check that the project setting also changed
await projectSettingsTab.click()
await expect(themeColorSetting).toHaveValue(settingValues.default)
>>>>>>> 1f27643b (Merge main)
}) })
}) })
}) })

7295
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

47
src-tauri/Cargo.toml Normal file
View File

@ -0,0 +1,47 @@
[package]
name = "app"
version = "0.1.0"
description = "The Zoo Modeling App"
authors = ["Zoo Engineers <eng@zoo.dev>"]
license = ""
repository = "https://github.com/KittyCAD/modeling-app"
default-run = "app"
edition = "2021"
rust-version = "1.70"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "2.0.0-beta.18", features = [] }
[dependencies]
anyhow = "1"
kcl-lib = { version = "0.2", path = "../src/wasm-lib/kcl" }
kittycad = "0.3.12"
log = "0.4.21"
mdns-sd = "0.11.1"
oauth2 = "4.4.2"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
serde_json = "1.0"
tauri = { version = "2.0.0-beta.23", features = [ "devtools", "unstable"] }
tauri-plugin-cli = { version = "2.0.0-beta.7" }
tauri-plugin-deep-link = { version = "2.0.0-beta.8" }
tauri-plugin-dialog = { version = "2.0.0-beta.6" }
tauri-plugin-fs = { version = "2.0.0-beta.10" }
tauri-plugin-http = { version = "2.0.0-beta.11" }
tauri-plugin-log = { version = "2.0.0-beta.7" }
tauri-plugin-os = { version = "2.0.0-beta.7" }
tauri-plugin-persisted-scope = { version = "2.0.0-beta.10" }
tauri-plugin-process = { version = "2.0.0-beta.7" }
tauri-plugin-shell = { version = "2.0.0-beta.8" }
tauri-plugin-updater = { version = "2.0.0-beta.9" }
tokio = { version = "1.37.0", features = ["time", "fs", "process"] }
toml = "0.8.2"
url = "2.5.0"
[features]
default = ["updater"]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
# DO NOT REMOVE!!
custom-protocol = ["tauri/custom-protocol"]
updater = []

View File

@ -28,6 +28,12 @@ import { CoreDumpManager } from 'lib/coredump'
import { UnitsMenu } from 'components/UnitsMenu' import { UnitsMenu } from 'components/UnitsMenu'
export function App() { export function App() {
<<<<<<< HEAD
||||||| parent of 1f27643b (Merge main)
useRefreshSettings(paths.FILE + 'SETTINGS')
=======
useRefreshSettings(PATHS.FILE + 'SETTINGS')
>>>>>>> 1f27643b (Merge main)
const { project, file } = useLoaderData() as IndexLoaderData const { project, file } = useLoaderData() as IndexLoaderData
useRefreshSettings(PATHS.FILE + 'SETTINGS') useRefreshSettings(PATHS.FILE + 'SETTINGS')
const navigate = useNavigate() const navigate = useNavigate()
@ -62,7 +68,14 @@ export function App() {
e.preventDefault() e.preventDefault()
}) })
useHotkeyWrapper( useHotkeyWrapper(
<<<<<<< HEAD
[isDesktop() ? 'mod + ,' : 'shift + mod + ,'], [isDesktop() ? 'mod + ,' : 'shift + mod + ,'],
||||||| parent of 1f27643b (Merge main)
[isTauri() ? 'mod + ,' : 'shift + mod + ,'],
() => navigate(filePath + paths.SETTINGS),
=======
[isTauri() ? 'mod + ,' : 'shift + mod + ,'],
>>>>>>> 1f27643b (Merge main)
() => navigate(filePath + PATHS.SETTINGS), () => navigate(filePath + PATHS.SETTINGS),
{ {
splitKey: '|', splitKey: '|',

View File

@ -76,13 +76,27 @@ const router = createRouter([
// Redirect to the file if we have a file path. // Redirect to the file if we have a file path.
if (projectStartupFile.length > 0) { if (projectStartupFile.length > 0) {
return redirect( return redirect(
<<<<<<< HEAD
PATHS.FILE + '/' + encodeURIComponent(projectStartupFile) PATHS.FILE + '/' + encodeURIComponent(projectStartupFile)
||||||| parent of 1f27643b (Merge main)
paths.FILE + '/' + encodeURIComponent(appState.current_file)
=======
PATHS.FILE + '/' + encodeURIComponent(appState.current_file)
>>>>>>> 1f27643b (Merge main)
) )
} }
} }
} }
<<<<<<< HEAD
return onDesktop return onDesktop
||||||| parent of 1f27643b (Merge main)
return inTauri
? redirect(paths.HOME)
: redirect(paths.FILE + '/%2F' + BROWSER_PROJECT_NAME)
=======
return inTauri
>>>>>>> 1f27643b (Merge main)
? redirect(PATHS.HOME) ? redirect(PATHS.HOME)
: redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME) : redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME)
}, },

View File

@ -53,10 +53,18 @@ export const FileMachineProvider = ({
if (event.data && 'name' in event.data) { if (event.data && 'name' in event.data) {
commandBarSend({ type: 'Close' }) commandBarSend({ type: 'Close' })
navigate( navigate(
<<<<<<< HEAD
`..${PATHS.FILE}/${encodeURIComponent( `..${PATHS.FILE}/${encodeURIComponent(
context.selectedDirectory + context.selectedDirectory +
window.electron.path.sep + window.electron.path.sep +
event.data.name event.data.name
||||||| parent of 1f27643b (Merge main)
`${paths.FILE}/${encodeURIComponent(
context.selectedDirectory + sep() + event.data.name
=======
`${PATHS.FILE}/${encodeURIComponent(
context.selectedDirectory + sep() + event.data.name
>>>>>>> 1f27643b (Merge main)
)}` )}`
) )
} else if ( } else if (
@ -65,7 +73,13 @@ export const FileMachineProvider = ({
event.data.path.endsWith(FILE_EXT) event.data.path.endsWith(FILE_EXT)
) { ) {
// Don't navigate to newly created directories // Don't navigate to newly created directories
<<<<<<< HEAD
navigate(`..${PATHS.FILE}/${encodeURIComponent(event.data.path)}`) navigate(`..${PATHS.FILE}/${encodeURIComponent(event.data.path)}`)
||||||| parent of 1f27643b (Merge main)
navigate(`${paths.FILE}/${encodeURIComponent(event.data.path)}`)
=======
navigate(`${PATHS.FILE}/${encodeURIComponent(event.data.path)}`)
>>>>>>> 1f27643b (Merge main)
} }
}, },
addFileToRenamingQueue: assign({ addFileToRenamingQueue: assign({
@ -198,13 +212,29 @@ export const FileMachineProvider = ({
if (oldPath === file.path && project?.path) { if (oldPath === file.path && project?.path) {
// If we just renamed the current file, navigate to the new path // If we just renamed the current file, navigate to the new path
<<<<<<< HEAD
navigate(`..${PATHS.FILE}/${encodeURIComponent(newPath)}`) navigate(`..${PATHS.FILE}/${encodeURIComponent(newPath)}`)
||||||| parent of 1f27643b (Merge main)
navigate(paths.FILE + '/' + encodeURIComponent(newPath))
=======
navigate(PATHS.FILE + '/' + encodeURIComponent(newPath))
>>>>>>> 1f27643b (Merge main)
} else if (file?.path.includes(oldPath)) { } else if (file?.path.includes(oldPath)) {
// If we just renamed a directory that the current file is in, navigate to the new path // If we just renamed a directory that the current file is in, navigate to the new path
navigate( navigate(
<<<<<<< HEAD
`..${PATHS.FILE}/${encodeURIComponent( `..${PATHS.FILE}/${encodeURIComponent(
file.path.replace(oldPath, newPath) file.path.replace(oldPath, newPath)
)}` )}`
||||||| parent of 1f27643b (Merge main)
paths.FILE +
'/' +
encodeURIComponent(file.path.replace(oldPath, newDirPath))
=======
PATHS.FILE +
'/' +
encodeURIComponent(file.path.replace(oldPath, newDirPath))
>>>>>>> 1f27643b (Merge main)
) )
} }
@ -260,7 +290,13 @@ export const FileMachineProvider = ({
file?.path.includes(event.data.path)) && file?.path.includes(event.data.path)) &&
project?.path project?.path
) { ) {
<<<<<<< HEAD
navigate(`../${PATHS.FILE}/${encodeURIComponent(project.path)}`) navigate(`../${PATHS.FILE}/${encodeURIComponent(project.path)}`)
||||||| parent of 1f27643b (Merge main)
navigate(paths.FILE + '/' + encodeURIComponent(project.path))
=======
navigate(PATHS.FILE + '/' + encodeURIComponent(project.path))
>>>>>>> 1f27643b (Merge main)
} }
return `Successfully deleted ${isDir ? 'folder' : 'file'} "${ return `Successfully deleted ${isDir ? 'folder' : 'file'} "${

View File

@ -1,4 +1,11 @@
<<<<<<< HEAD
import type { IndexLoaderData } from 'lib/types' import type { IndexLoaderData } from 'lib/types'
||||||| parent of 1f27643b (Merge main)
import type { FileEntry, IndexLoaderData } from 'lib/types'
import { paths } from 'lib/paths'
=======
import type { FileEntry, IndexLoaderData } from 'lib/types'
>>>>>>> 1f27643b (Merge main)
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
import { ActionButton } from './ActionButton' import { ActionButton } from './ActionButton'
import Tooltip from './Tooltip' import Tooltip from './Tooltip'
@ -476,10 +483,16 @@ export const FileTreeInner = ({
}, [documentHasFocus]) }, [documentHasFocus])
return ( return (
<<<<<<< HEAD
<div <div
className="overflow-auto pb-12 absolute inset-0" className="overflow-auto pb-12 absolute inset-0"
data-testid="file-pane-scroll-container" data-testid="file-pane-scroll-container"
> >
||||||| parent of 1f27643b (Merge main)
<div className="overflow-auto max-h-full pb-12">
=======
<div className="overflow-auto pb-12 absolute inset-0">
>>>>>>> 1f27643b (Merge main)
<ul <ul
className="m-0 p-0 text-sm" className="m-0 p-0 text-sm"
onClickCapture={(e) => { onClickCapture={(e) => {

View File

@ -3,8 +3,16 @@ import Tooltip from './Tooltip'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { CustomIcon } from './CustomIcon' import { CustomIcon } from './CustomIcon'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
<<<<<<< HEAD
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
import { createAndOpenNewProject } from 'lib/desktopFS' import { createAndOpenNewProject } from 'lib/desktopFS'
||||||| parent of 1f27643b (Merge main)
import { createAndOpenNewProject } from 'lib/tauriFS'
import { paths } from 'lib/paths'
=======
import { createAndOpenNewProject } from 'lib/tauriFS'
import { PATHS } from 'lib/paths'
>>>>>>> 1f27643b (Merge main)
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath' import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
import { useLspContext } from './LspProvider' import { useLspContext } from './LspProvider'
import { openExternalBrowserIfDesktop } from 'lib/openWindow' import { openExternalBrowserIfDesktop } from 'lib/openWindow'

View File

@ -93,7 +93,15 @@ export function LowerRightControls({
<Link <Link
to={ to={
location.pathname.includes(PATHS.FILE) location.pathname.includes(PATHS.FILE)
<<<<<<< HEAD
? filePath + PATHS.SETTINGS + '?tab=project' ? filePath + PATHS.SETTINGS + '?tab=project'
||||||| parent of 1f27643b (Merge main)
location.pathname.includes(paths.FILE)
? filePath + paths.SETTINGS + '?tab=project'
: paths.HOME + paths.SETTINGS
=======
? filePath + PATHS.SETTINGS_PROJECT
>>>>>>> 1f27643b (Merge main)
: PATHS.HOME + PATHS.SETTINGS : PATHS.HOME + PATHS.SETTINGS
} }
data-testid="settings-link" data-testid="settings-link"

View File

@ -15,7 +15,14 @@ import { Extension } from '@codemirror/state'
import { LanguageSupport } from '@codemirror/language' import { LanguageSupport } from '@codemirror/language'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
<<<<<<< HEAD
import { FileEntry } from 'lib/project' import { FileEntry } from 'lib/project'
||||||| parent of 1f27643b (Merge main)
import { paths } from 'lib/paths'
import { FileEntry } from 'lib/types'
=======
import { FileEntry } from 'lib/types'
>>>>>>> 1f27643b (Merge main)
import Worker from 'editor/plugins/lsp/worker.ts?worker' import Worker from 'editor/plugins/lsp/worker.ts?worker'
import { import {
KclWorkerOptions, KclWorkerOptions,

View File

@ -2,7 +2,14 @@ import { Popover, Transition } from '@headlessui/react'
import { ActionButton, ActionButtonProps } from './ActionButton' import { ActionButton, ActionButtonProps } from './ActionButton'
import { type IndexLoaderData } from 'lib/types' import { type IndexLoaderData } from 'lib/types'
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
<<<<<<< HEAD
import { isDesktop } from '../lib/isDesktop' import { isDesktop } from '../lib/isDesktop'
||||||| parent of 1f27643b (Merge main)
import { paths } from 'lib/paths'
import { isTauri } from '../lib/isTauri'
=======
import { isTauri } from '../lib/isTauri'
>>>>>>> 1f27643b (Merge main)
import { Link, useLocation, useNavigate } from 'react-router-dom' import { Link, useLocation, useNavigate } from 'react-router-dom'
import { Fragment, useMemo } from 'react' import { Fragment, useMemo } from 'react'
import { Logo } from './Logo' import { Logo } from './Logo'

View File

@ -15,8 +15,16 @@ import { SettingsFieldInput } from './SettingsFieldInput'
import { getInitialDefaultDir } from 'lib/desktop' import { getInitialDefaultDir } from 'lib/desktop'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { APP_VERSION } from 'routes/Settings' import { APP_VERSION } from 'routes/Settings'
<<<<<<< HEAD
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
import { createAndOpenNewProject, getSettingsFolderPaths } from 'lib/desktopFS' import { createAndOpenNewProject, getSettingsFolderPaths } from 'lib/desktopFS'
||||||| parent of 1f27643b (Merge main)
import { createAndOpenNewProject, getSettingsFolderPaths } from 'lib/tauriFS'
import { paths } from 'lib/paths'
=======
import { createAndOpenNewProject, getSettingsFolderPaths } from 'lib/tauriFS'
import { PATHS } from 'lib/paths'
>>>>>>> 1f27643b (Merge main)
import { useDotDotSlash } from 'hooks/useDotDotSlash' import { useDotDotSlash } from 'hooks/useDotDotSlash'
import { ForwardedRef, forwardRef, useEffect } from 'react' import { ForwardedRef, forwardRef, useEffect } from 'react'
import { useLspContext } from 'components/LspProvider' import { useLspContext } from 'components/LspProvider'
@ -45,12 +53,20 @@ export const AllSettingsFields = forwardRef(
location.pathname location.pathname
.replace(PATHS.FILE + '/', '') .replace(PATHS.FILE + '/', '')
.replace(PATHS.SETTINGS, '') .replace(PATHS.SETTINGS, '')
<<<<<<< HEAD
.slice( .slice(
0, 0,
decodeURI(location.pathname).lastIndexOf( decodeURI(location.pathname).lastIndexOf(
window.electron.path.sep window.electron.path.sep
) )
) )
||||||| parent of 1f27643b (Merge main)
.replace(paths.FILE + '/', '')
.replace(paths.SETTINGS, '')
.slice(0, decodeURI(location.pathname).lastIndexOf(sep()))
=======
.slice(0, decodeURI(location.pathname).lastIndexOf(sep()))
>>>>>>> 1f27643b (Merge main)
) )
: undefined : undefined

View File

@ -1,5 +1,12 @@
import { useMachine } from '@xstate/react' import { useMachine } from '@xstate/react'
<<<<<<< HEAD
import { useNavigate, useRouteLoaderData, useLocation } from 'react-router-dom' import { useNavigate, useRouteLoaderData, useLocation } from 'react-router-dom'
||||||| parent of 1f27643b (Merge main)
import { useNavigate, useRouteLoaderData } from 'react-router-dom'
import { paths } from 'lib/paths'
=======
import { useNavigate, useRouteLoaderData } from 'react-router-dom'
>>>>>>> 1f27643b (Merge main)
import { PATHS } from 'lib/paths' import { PATHS } from 'lib/paths'
import { authMachine, TOKEN_PERSIST_KEY } from '../machines/authMachine' import { authMachine, TOKEN_PERSIST_KEY } from '../machines/authMachine'
import withBaseUrl from '../lib/withBaseURL' import withBaseUrl from '../lib/withBaseURL'
@ -302,7 +309,14 @@ export const SettingsAuthProviderBase = ({
logout() logout()
}, },
goToIndexPage: () => { goToIndexPage: () => {
<<<<<<< HEAD
if (location.pathname.includes(PATHS.SIGN_IN)) { if (location.pathname.includes(PATHS.SIGN_IN)) {
||||||| parent of 1f27643b (Merge main)
if (window.location.pathname.includes(paths.SIGN_IN)) {
navigate(paths.INDEX)
=======
if (window.location.pathname.includes(PATHS.SIGN_IN)) {
>>>>>>> 1f27643b (Merge main)
navigate(PATHS.INDEX) navigate(PATHS.INDEX)
} }
}, },

View File

@ -584,7 +584,7 @@ describe('Testing removeSingleConstraintInfo', () => {
intersectTag: a, intersectTag: a,
offset: 0 + 0 offset: 0 + 0
}, %) }, %)
|> tangentialArcTo([3.14 + 0, 13.14 + 0], %)` |> tangentialArcTo([3.14 + 0, 13.14 + 0], false, %)`
test.each([ test.each([
[' line([3 + 0, 4], %)', 'arrayIndex', 1], [' line([3 + 0, 4], %)', 'arrayIndex', 1],
[ [
@ -626,7 +626,7 @@ describe('Testing removeSingleConstraintInfo', () => {
'objectProperty', 'objectProperty',
'offset', 'offset',
], ],
['tangentialArcTo([3.14 + 0, 13.14], %)', 'arrayIndex', 1], ['tangentialArcTo([3.14 + 0, 13.14], false, %)', 'arrayIndex', 1],
])('stdlib fn: %s', async (expectedFinish, key, value) => { ])('stdlib fn: %s', async (expectedFinish, key, value) => {
const ast = parse(code) const ast = parse(code)
if (err(ast)) throw ast if (err(ast)) throw ast

View File

@ -256,6 +256,14 @@ const runFilletTest = async (
return new Error('Path to extrude node not found') return new Error('Path to extrude node not found')
} }
<<<<<<< HEAD
||||||| parent of 1f27643b (Merge main)
// const radius = createLiteral(5) as Value
=======
// const radius = createLiteral(5) as Expr
>>>>>>> 1f27643b (Merge main)
const result = addFillet(ast, pathToSegmentNode, pathToExtrudeNode, radius) const result = addFillet(ast, pathToSegmentNode, pathToExtrudeNode, radius)
if (err(result)) { if (err(result)) {
return result return result
@ -278,8 +286,8 @@ describe('Testing addFillet', () => {
|> line([60.04, -55.72], %) |> line([60.04, -55.72], %)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %) |> line([-87.24, -47.08], %)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -293,8 +301,8 @@ describe('Testing addFillet', () => {
|> line([60.04, -55.72], %, $seg01) |> line([60.04, -55.72], %, $seg01)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %) |> line([-87.24, -47.08], %)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -321,8 +329,8 @@ const extrude001 = extrude(50, sketch001)
|> line([60.04, -55.72], %) |> line([60.04, -55.72], %)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %, $seg01) |> line([-87.24, -47.08], %, $seg01)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -336,8 +344,8 @@ const extrude001 = extrude(50, sketch001)
|> line([60.04, -55.72], %, $seg02) |> line([60.04, -55.72], %, $seg02)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %, $seg01) |> line([-87.24, -47.08], %, $seg01)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -364,8 +372,8 @@ const extrude001 = extrude(50, sketch001)
|> line([60.04, -55.72], %) |> line([60.04, -55.72], %)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %, $seg03) |> line([-87.24, -47.08], %, $seg03)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -379,8 +387,8 @@ const extrude001 = extrude(50, sketch001)
|> line([60.04, -55.72], %) |> line([60.04, -55.72], %)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %, $seg03) |> line([-87.24, -47.08], %, $seg03)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -406,8 +414,8 @@ const extrude001 = extrude(50, sketch001)
|> line([60.04, -55.72], %) |> line([60.04, -55.72], %)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %, $seg03) |> line([-87.24, -47.08], %, $seg03)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)
@ -421,8 +429,8 @@ const extrude001 = extrude(50, sketch001)
|> line([60.04, -55.72], %, $seg01) |> line([60.04, -55.72], %, $seg01)
|> line([1.29, -115.74], %) |> line([1.29, -115.74], %)
|> line([-87.24, -47.08], %, $seg03) |> line([-87.24, -47.08], %, $seg03)
|> tangentialArcTo([56.15, -94.58], %) |> tangentialArcTo([56.15, -94.58], false, %)
|> tangentialArcTo([14.68, -104.52], %) |> tangentialArcTo([14.68, -104.52], false, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
const extrude001 = extrude(50, sketch001) const extrude001 = extrude(50, sketch001)

View File

@ -4,7 +4,12 @@ import {
ObjectExpression, ObjectExpression,
PathToNode, PathToNode,
Program, Program,
<<<<<<< HEAD
ProgramMemory, ProgramMemory,
||||||| parent of 1f27643b (Merge main)
Value,
=======
>>>>>>> 1f27643b (Merge main)
Expr, Expr,
VariableDeclaration, VariableDeclaration,
VariableDeclarator, VariableDeclarator,
@ -159,7 +164,15 @@ export function addFillet(
ast: Program, ast: Program,
pathToSegmentNode: PathToNode, pathToSegmentNode: PathToNode,
pathToExtrudeNode: PathToNode, pathToExtrudeNode: PathToNode,
<<<<<<< HEAD
radius: Expr = createLiteral(5) radius: Expr = createLiteral(5)
||||||| parent of 1f27643b (Merge main)
radius = createLiteral(5) as Value
// shouldPipe = false, // TODO: Implement this feature
=======
radius = createLiteral(5) as Expr
// shouldPipe = false, // TODO: Implement this feature
>>>>>>> 1f27643b (Merge main)
): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error { ): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error {
// Clone AST to ensure safe mutations // Clone AST to ensure safe mutations
const astClone = structuredClone(ast) const astClone = structuredClone(ast)

View File

@ -270,7 +270,7 @@ describe('testing getConstraintInfo', () => {
intersectTag: 'a', intersectTag: 'a',
offset: 0 offset: 0
}, %) }, %)
|> tangentialArcTo([3.14, 13.14], %)` |> tangentialArcTo([3.14, 13.14], false, %)`
const ast = parse(code) const ast = parse(code)
test.each([ test.each([
[ [
@ -629,7 +629,7 @@ describe('testing getConstraintInfo', () => {
intersectTag: 'a', intersectTag: 'a',
offset: 0 offset: 0
}, %) }, %)
|> tangentialArcTo([3.14, 13.14], %)` |> tangentialArcTo([3.14, 13.14], false, %)`
const ast = parse(code) const ast = parse(code)
test.each([ test.each([
[ [
@ -783,7 +783,7 @@ describe('testing getConstraintInfo', () => {
intersectTag: 'a', intersectTag: 'a',
offset: 0 + 0 offset: 0 + 0
}, %) }, %)
|> tangentialArcTo([3.14 + 0, 13.14 + 0], %)` |> tangentialArcTo([3.14 + 0, 13.14 + 0], false, %)`
const ast = parse(code) const ast = parse(code)
test.each([ test.each([
[ [

View File

@ -812,6 +812,7 @@ export const tangentialArcTo: SketchLineHelper = {
} }
const newLine = createCallExpression('tangentialArcTo', [ const newLine = createCallExpression('tangentialArcTo', [
createArrayExpression([toX, toY]), createArrayExpression([toX, toY]),
createLiteral(false),
createPipeSubstitution(), createPipeSubstitution(),
]) ])
if (pipe.type === 'PipeExpression') { if (pipe.type === 'PipeExpression') {

View File

@ -25,6 +25,7 @@ type OnboardingPaths = {
const SETTINGS = '/settings' as const const SETTINGS = '/settings' as const
<<<<<<< HEAD
export type ProjectRoute = { export type ProjectRoute = {
projectName: string | null projectName: string | null
projectPath: string projectPath: string
@ -32,6 +33,10 @@ export type ProjectRoute = {
currentFilePath: string | null currentFilePath: string | null
} }
||||||| parent of 1f27643b (Merge main)
export const paths = {
=======
>>>>>>> 1f27643b (Merge main)
export const PATHS = { export const PATHS = {
INDEX: '/', INDEX: '/',
HOME: '/home', HOME: '/home',

View File

@ -1,7 +1,15 @@
import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom' import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'
import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types' import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types'
<<<<<<< HEAD
import { getProjectMetaByRouteId, PATHS } from './paths' import { getProjectMetaByRouteId, PATHS } from './paths'
import { isDesktop } from './isDesktop' import { isDesktop } from './isDesktop'
||||||| parent of 1f27643b (Merge main)
import { isTauri } from './isTauri'
import { getProjectMetaByRouteId, paths } from './paths'
=======
import { isTauri } from './isTauri'
import { getProjectMetaByRouteId, PATHS } from './paths'
>>>>>>> 1f27643b (Merge main)
import { BROWSER_PATH } from 'lib/paths' import { BROWSER_PATH } from 'lib/paths'
import { import {
BROWSER_FILE_NAME, BROWSER_FILE_NAME,
@ -10,6 +18,15 @@ import {
} from 'lib/constants' } from 'lib/constants'
import { loadAndValidateSettings } from './settings/settingsUtils' import { loadAndValidateSettings } from './settings/settingsUtils'
import makeUrlPathRelative from './makeUrlPathRelative' import makeUrlPathRelative from './makeUrlPathRelative'
<<<<<<< HEAD
||||||| parent of 1f27643b (Merge main)
import { sep } from '@tauri-apps/api/path'
import { readTextFile } from '@tauri-apps/plugin-fs'
import { codeManager, kclManager } from 'lib/singletons'
=======
import { sep } from '@tauri-apps/api/path'
import { readTextFile } from '@tauri-apps/plugin-fs'
>>>>>>> 1f27643b (Merge main)
import { codeManager } from 'lib/singletons' import { codeManager } from 'lib/singletons'
import { fileSystemManager } from 'lang/std/fileSystemManager' import { fileSystemManager } from 'lang/std/fileSystemManager'
import { import {
@ -86,6 +103,7 @@ export const fileLoader: LoaderFunction = async (
const { projectName, projectPath, currentFileName, currentFilePath } = const { projectName, projectPath, currentFileName, currentFilePath } =
projectPathData projectPathData
<<<<<<< HEAD
const urlObj = new URL(routerData.request.url) const urlObj = new URL(routerData.request.url)
let code = '' let code = ''
@ -120,8 +138,50 @@ export const fileLoader: LoaderFunction = async (
// the file system and not the editor. // the file system and not the editor.
codeManager.updateCurrentFilePath(currentFilePath) codeManager.updateCurrentFilePath(currentFilePath)
codeManager.updateCodeStateEditor(code) codeManager.updateCodeStateEditor(code)
||||||| parent of 1f27643b (Merge main)
if (!current_file_name || !current_file_path || !project_name) {
return redirect(
`${paths.FILE}/${encodeURIComponent(
`${params.id}${isTauri() ? sep() : '/'}${PROJECT_ENTRYPOINT}`
)}`
)
=======
if (!current_file_name || !current_file_path || !project_name) {
return redirect(
`${PATHS.FILE}/${encodeURIComponent(
`${params.id}${isTauri() ? sep() : '/'}${PROJECT_ENTRYPOINT}`
)}`
)
>>>>>>> 1f27643b (Merge main)
} }
<<<<<<< HEAD
||||||| parent of 1f27643b (Merge main)
// TODO: PROJECT_ENTRYPOINT is hardcoded
// until we support setting a project's entrypoint file
const code = await readTextFile(current_file_path)
// Update both the state and the editor's code.
// We explicitly do not write to the file here since we are loading from
// the file system and not the editor.
codeManager.updateCurrentFilePath(current_file_path)
codeManager.updateCodeStateEditor(code)
// We don't want to call await on execute code since we don't want to block the UI
kclManager.executeCode(true)
=======
// TODO: PROJECT_ENTRYPOINT is hardcoded
// until we support setting a project's entrypoint file
const code = await readTextFile(current_file_path)
// Update both the state and the editor's code.
// We explicitly do not write to the file here since we are loading from
// the file system and not the editor.
codeManager.updateCurrentFilePath(current_file_path)
codeManager.updateCodeStateEditor(code)
>>>>>>> 1f27643b (Merge main)
// Set the file system manager to the project path // Set the file system manager to the project path
// So that WASM gets an updated path for operations // So that WASM gets an updated path for operations
fileSystemManager.dir = projectPath fileSystemManager.dir = projectPath
@ -181,7 +241,14 @@ export const fileLoader: LoaderFunction = async (
export const homeLoader: LoaderFunction = async (): Promise< export const homeLoader: LoaderFunction = async (): Promise<
HomeLoaderData | Response HomeLoaderData | Response
> => { > => {
<<<<<<< HEAD
if (!isDesktop()) { if (!isDesktop()) {
||||||| parent of 1f27643b (Merge main)
if (!isTauri()) {
return redirect(paths.FILE + '/%2F' + BROWSER_PROJECT_NAME)
=======
if (!isTauri()) {
>>>>>>> 1f27643b (Merge main)
return redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME) return redirect(PATHS.FILE + '/%2F' + BROWSER_PROJECT_NAME)
} }
const { configuration } = await loadAndValidateSettings() const { configuration } = await loadAndValidateSettings()

View File

@ -42,7 +42,12 @@ import { Project } from 'lib/project'
// This route only opens in the desktop context for now, // This route only opens in the desktop context for now,
// as defined in Router.tsx, so we can use the desktop APIs and types. // as defined in Router.tsx, so we can use the desktop APIs and types.
const Home = () => { const Home = () => {
<<<<<<< HEAD
const { projects: loadedProjects } = useLoaderData() as HomeLoaderData const { projects: loadedProjects } = useLoaderData() as HomeLoaderData
||||||| parent of 1f27643b (Merge main)
useRefreshSettings(paths.HOME + 'SETTINGS')
=======
>>>>>>> 1f27643b (Merge main)
useRefreshSettings(PATHS.HOME + 'SETTINGS') useRefreshSettings(PATHS.HOME + 'SETTINGS')
const { commandBarSend } = useCommandsContext() const { commandBarSend } = useCommandsContext()
const navigate = useNavigate() const navigate = useNavigate()
@ -60,7 +65,14 @@ const Home = () => {
e.preventDefault() e.preventDefault()
}) })
useHotkeys( useHotkeys(
<<<<<<< HEAD
isDesktop() ? 'mod+,' : 'shift+mod+,', isDesktop() ? 'mod+,' : 'shift+mod+,',
||||||| parent of 1f27643b (Merge main)
isTauri() ? 'mod+,' : 'shift+mod+,',
() => navigate(paths.HOME + paths.SETTINGS),
=======
isTauri() ? 'mod+,' : 'shift+mod+,',
>>>>>>> 1f27643b (Merge main)
() => navigate(PATHS.HOME + PATHS.SETTINGS), () => navigate(PATHS.HOME + PATHS.SETTINGS),
{ {
splitKey: '|', splitKey: '|',
@ -280,8 +292,14 @@ const Home = () => {
<p className="my-4 text-sm text-chalkboard-80 dark:text-chalkboard-30"> <p className="my-4 text-sm text-chalkboard-80 dark:text-chalkboard-30">
Loaded from{' '} Loaded from{' '}
<Link <Link
<<<<<<< HEAD
data-testid="project-directory-settings-link" data-testid="project-directory-settings-link"
to={`${PATHS.HOME + PATHS.SETTINGS_USER}#projectDirectory`} to={`${PATHS.HOME + PATHS.SETTINGS_USER}#projectDirectory`}
||||||| parent of 1f27643b (Merge main)
to="settings?tab=user#projectDirectory"
=======
to={`${PATHS.SETTINGS_USER}#projectDirectory`}
>>>>>>> 1f27643b (Merge main)
className="text-chalkboard-90 dark:text-chalkboard-20 underline underline-offset-2" className="text-chalkboard-90 dark:text-chalkboard-20 underline underline-offset-2"
> >
{settings.app.projectDirectory.current} {settings.app.projectDirectory.current}

View File

@ -3309,7 +3309,7 @@ mod snapshot_tests {
a, a,
r#"const boxSketch = startSketchAt([0, 0]) r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %) |> line([0, 10], %)
|> tangentialArc([-5, 5], %) |> tangentialArcTo([-5, 5], true, %)
|> line([5, -15], %) |> line([5, -15], %)
|> extrude(10, %) |> extrude(10, %)
"# "#

View File

@ -5,7 +5,7 @@ use kittycad::types::OkWebSocketResponseData;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use crate::{ use crate::{
ast::types::{parse_json_number_as_f64, TagDeclarator}, ast::types::{parse_json_number_as_f64, KclNone, TagDeclarator},
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{ executor::{
DynamicState, ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, KclValue, Metadata, DynamicState, ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, KclValue, Metadata,
@ -495,6 +495,9 @@ where
{ {
fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> { fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
let Some(arg) = args.args.get(i) else { return Ok(None) }; let Some(arg) = args.args.get(i) else { return Ok(None) };
if let Some(_kcl_none) = KclNone::from_mem_item(arg) {
return Ok(None);
}
let Some(val) = T::from_mem_item(arg) else { let Some(val) = T::from_mem_item(arg) else {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
message: format!( message: format!(
@ -624,6 +627,7 @@ impl_from_arg_via_json!(u32);
impl_from_arg_via_json!(u64); impl_from_arg_via_json!(u64);
impl_from_arg_via_json!(f64); impl_from_arg_via_json!(f64);
impl_from_arg_via_json!(bool); impl_from_arg_via_json!(bool);
impl_from_arg_via_json!(KclNone);
impl_from_arg_for_array!(2); impl_from_arg_for_array!(2);
impl_from_arg_for_array!(3); impl_from_arg_for_array!(3);

View File

@ -14,7 +14,7 @@ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{ executor::{
BasePath, ExtrudeGroup, Face, GeoMeta, KclValue, Path, Plane, PlaneType, Point2d, Point3d, SketchGroup, BasePath, ExtrudeGroup, Face, GeoMeta, KclValue, Path, Plane, PlaneType, Point2d, Point3d, SketchGroup,
SketchGroupSet, SketchSurface, SourceRange, TagEngineInfo, TagIdentifier, UserVal, SketchGroupSet, SketchSurface, TagEngineInfo, TagIdentifier, UserVal,
}, },
std::{ std::{
utils::{ utils::{
@ -1634,8 +1634,6 @@ pub enum TangentialArcData {
/// Offset of the arc, in degrees. /// Offset of the arc, in degrees.
offset: f64, offset: f64,
}, },
/// A point where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
Point([f64; 2]),
} }
/// Draw a tangential arc. /// Draw a tangential arc.
@ -1647,8 +1645,11 @@ pub async fn tangential_arc(args: Args) -> Result<KclValue, KclError> {
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
} }
/// Starting at the current sketch's origin, draw a curved line segment along /// Draw a curved line segment along some part of an imaginary circle of the specified radius.
/// some part of an imaginary circle of the specified radius. ///
/// If `relative` is true, the curve starts at the end of the previous path segment
/// (i.e. the location of the "pen" which draws these lines). If `relative` is false,
/// starts from the current sketch's origin.
/// ///
/// The arc is constructed such that the last line segment is placed tangent /// The arc is constructed such that the last line segment is placed tangent
/// to the imaginary circle of the specified radius. The resulting arc is the /// to the imaginary circle of the specified radius. The resulting arc is the
@ -1728,13 +1729,6 @@ async fn inner_tangential_arc(
.await?; .await?;
(center, to.into(), ccw) (center, to.into(), ccw)
} }
TangentialArcData::Point(to) => {
args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, &to)).await?;
// TODO: Figure out these calculations.
let ccw = false;
let center = Point2d { x: 0.0, y: 0.0 };
(center, to, ccw)
}
}; };
let current_path = Path::TangentialArc { let current_path = Path::TangentialArc {
@ -1775,32 +1769,13 @@ fn tan_arc_to(sketch_group: &SketchGroup, to: &[f64; 2]) -> ModelingCmd {
} }
} }
fn too_few_args(source_range: SourceRange) -> KclError {
KclError::Syntax(KclErrorDetails {
source_ranges: vec![source_range],
message: "too few arguments".to_owned(),
})
}
fn get_arg<I: Iterator>(it: &mut I, src: SourceRange) -> Result<I::Item, KclError> {
it.next().ok_or_else(|| too_few_args(src))
}
/// Draw a tangential arc to a specific point. /// Draw a tangential arc to a specific point.
pub async fn tangential_arc_to(args: Args) -> Result<KclValue, KclError> { pub async fn tangential_arc_to(args: Args) -> Result<KclValue, KclError> {
let src = args.source_range;
// Get arguments to function call // Get arguments to function call
let mut it = args.args.iter(); let (to, relative, sketch_group, tag): ([f64; 2], bool, SketchGroup, Option<TagDeclarator>) =
let to: [f64; 2] = get_arg(&mut it, src)?.get_json()?; super::args::FromArgs::from_args(&args, 0)?;
let sketch_group: SketchGroup = get_arg(&mut it, src)?.get_json()?;
let tag = if let Ok(memory_item) = get_arg(&mut it, src) {
memory_item.get_json_opt()?
} else {
None
};
let new_sketch_group = inner_tangential_arc_to(to, sketch_group, tag, args).await?; let new_sketch_group = inner_tangential_arc_to(to, relative, sketch_group, tag, args).await?;
Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group))
} }
@ -1815,7 +1790,7 @@ pub async fn tangential_arc_to(args: Args) -> Result<KclValue, KclError> {
/// angle: 60, /// angle: 60,
/// length: 10, /// length: 10,
/// }, %) /// }, %)
/// |> tangentialArcTo([15, 15], %) /// |> tangentialArcTo([15, 15], false, %)
/// |> line([10, -15], %) /// |> line([10, -15], %)
/// |> close(%) /// |> close(%)
/// ///
@ -1826,6 +1801,7 @@ pub async fn tangential_arc_to(args: Args) -> Result<KclValue, KclError> {
}] }]
async fn inner_tangential_arc_to( async fn inner_tangential_arc_to(
to: [f64; 2], to: [f64; 2],
relative: bool,
sketch_group: SketchGroup, sketch_group: SketchGroup,
tag: Option<TagDeclarator>, tag: Option<TagDeclarator>,
args: Args, args: Args,
@ -1845,9 +1821,13 @@ async fn inner_tangential_arc_to(
obtuse: true, obtuse: true,
}); });
let delta = [to_x - from.x, to_y - from.y]; let to = if relative {
[to_x, to_y]
} else {
[to_x - from.x, to_y - from.y]
};
let id = uuid::Uuid::new_v4(); let id = uuid::Uuid::new_v4();
args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, &delta)).await?; args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, &to)).await?;
let current_path = Path::TangentialArcTo { let current_path = Path::TangentialArcTo {
base: BasePath { base: BasePath {

View File

@ -9,40 +9,40 @@ let corner_radius = 5.0
// because your wrist isn't a perfect cylindrical surface // because your wrist isn't a perfect cylindrical surface
let brace_base = startSketchAt([corner_radius, 0]) let brace_base = startSketchAt([corner_radius, 0])
|> line([width - corner_radius, 0.0], %) |> line([width - corner_radius, 0.0], %)
|> tangentialArc([corner_radius, corner_radius], %) |> tangentialArcTo([corner_radius, corner_radius], true, %)
|> yLine(25.0 - corner_radius, %) |> yLine(25.0 - corner_radius, %)
|> tangentialArc([-corner_radius, corner_radius], %) |> tangentialArcTo([-corner_radius, corner_radius], true, %)
|> xLine(-(d_wrist_circumference[0] - (corner_radius * 2)), %) |> xLine(-(d_wrist_circumference[0] - (corner_radius * 2)), %)
|> tangentialArc([-corner_radius, corner_radius], %) |> tangentialArcTo([-corner_radius, corner_radius], true, %)
|> yLine(length - 25.0 - 23.0 - (corner_radius * 2), %) |> yLine(length - 25.0 - 23.0 - (corner_radius * 2), %)
|> tangentialArc([corner_radius, corner_radius], %) |> tangentialArcTo([corner_radius, corner_radius], true, %)
|> xLine(15.0 - (corner_radius * 2), %) |> xLine(15.0 - (corner_radius * 2), %)
|> tangentialArc([corner_radius, corner_radius], %) |> tangentialArcTo([corner_radius, corner_radius], true, %)
|> yLine(23.0 - corner_radius, %) |> yLine(23.0 - corner_radius, %)
|> tangentialArc([-corner_radius, corner_radius], %) |> tangentialArcTo([-corner_radius, corner_radius], true, %)
|> xLine(-(hand_thickness + 15.0 + 15.0 - (corner_radius * 2)), %) |> xLine(-(hand_thickness + 15.0 + 15.0 - (corner_radius * 2)), %)
|> tangentialArc([-corner_radius, -corner_radius], %) |> tangentialArcTo([-corner_radius, -corner_radius], true, %)
|> yLine(-(23.0 - corner_radius), %) |> yLine(-(23.0 - corner_radius), %)
|> tangentialArc([corner_radius, -corner_radius], %) |> tangentialArcTo([corner_radius, -corner_radius], true, %)
|> xLine(15.0 - (corner_radius * 2), %) |> xLine(15.0 - (corner_radius * 2), %)
|> tangentialArc([corner_radius, -corner_radius], %) |> tangentialArcTo([corner_radius, -corner_radius], true, %)
|> yLine(-(length - 25.0 - 23.0 - (corner_radius * 2)), %) |> yLine(-(length - 25.0 - 23.0 - (corner_radius * 2)), %)
|> tangentialArc([-corner_radius, -corner_radius], %) |> tangentialArcTo([-corner_radius, -corner_radius], true, %)
|> xLine(-(d_wrist_circumference[1] + d_wrist_circumference[2] + d_wrist_circumference[3] - hand_thickness - corner_radius), %) |> xLine(-(d_wrist_circumference[1] + d_wrist_circumference[2] + d_wrist_circumference[3] - hand_thickness - corner_radius), %)
|> tangentialArc([-corner_radius, -corner_radius], %) |> tangentialArcTo([-corner_radius, -corner_radius], true, %)
|> yLine(-(25.0 - corner_radius), %) |> yLine(-(25.0 - corner_radius), %)
|> tangentialArc([corner_radius, -corner_radius], %) |> tangentialArcTo([corner_radius, -corner_radius], true, %)
|> close(%) |> close(%)
let inner = startSketchAt([0, 0]) let inner = startSketchAt([0, 0])
|> xLine(1.0, %) |> xLine(1.0, %)
|> tangentialArc([corner_radius, corner_radius], %) |> tangentialArcTo([corner_radius, corner_radius], true, %)
|> yLine(25.0 - (corner_radius * 2), %) |> yLine(25.0 - (corner_radius * 2), %)
|> tangentialArc([-corner_radius, corner_radius], %) |> tangentialArcTo([-corner_radius, corner_radius], true, %)
|> xLine(-1.0, %) |> xLine(-1.0, %)
|> tangentialArc([-corner_radius, -corner_radius], %) |> tangentialArcTo([-corner_radius, -corner_radius], true, %)
|> yLine(-(25.0 - (corner_radius * 2)), %) |> yLine(-(25.0 - (corner_radius * 2)), %)
|> tangentialArc([corner_radius, -corner_radius], %) |> tangentialArcTo([corner_radius, -corner_radius], true, %)
|> close(%) |> close(%)
let final = brace_base let final = brace_base

View File

@ -186,7 +186,7 @@ async fn kcl_test_negative_args() {
async fn kcl_test_basic_tangential_arc_with_point() { async fn kcl_test_basic_tangential_arc_with_point() {
let code = r#"const boxSketch = startSketchAt([0, 0]) let code = r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %) |> line([0, 10], %)
|> tangentialArc([-5, 5], %) |> tangentialArcTo([-5, 5], true, %)
|> line([5, -15], %) |> line([5, -15], %)
|> extrude(10, %) |> extrude(10, %)
"#; "#;
@ -199,7 +199,7 @@ async fn kcl_test_basic_tangential_arc_with_point() {
async fn kcl_test_basic_tangential_arc_to() { async fn kcl_test_basic_tangential_arc_to() {
let code = r#"const boxSketch = startSketchAt([0, 0]) let code = r#"const boxSketch = startSketchAt([0, 0])
|> line([0, 10], %) |> line([0, 10], %)
|> tangentialArcTo([-5, 15], %) |> tangentialArcTo([-5, 15], false, %)
|> line([5, -15], %) |> line([5, -15], %)
|> extrude(10, %) |> extrude(10, %)
"#; "#;
@ -332,7 +332,7 @@ const thing = other_circle([2, 2], 20)
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn kcl_test_rounded_with_holes() { async fn kcl_test_rounded_with_holes() {
let code = r#"fn tarc = (to, sketchGroup, tag?) => { let code = r#"fn tarc = (to, sketchGroup, tag?) => {
return tangentialArcTo(to, sketchGroup, tag) return tangentialArcTo(to, false, sketchGroup, tag)
} }
fn roundedRectangle = (pos, w, l, cornerRadius) => { fn roundedRectangle = (pos, w, l, cornerRadius) => {
@ -1341,7 +1341,7 @@ async fn kcl_test_error_empty_start_sketch_on_string() {
|> line([190.03, -118.13], %) |> line([190.03, -118.13], %)
|> line([-33.38, -202.86], %) |> line([-33.38, -202.86], %)
|> line([-315.86, -64.2], %) |> line([-315.86, -64.2], %)
|> tangentialArcTo([-147.66, 121.34], %) |> tangentialArcTo([-147.66, 121.34], false, %)
|> close(%) |> close(%)
|> extrude(100, %) |> extrude(100, %)