diff --git a/e2e/playwright/flow-tests.spec.ts b/e2e/playwright/flow-tests.spec.ts index 028cd341c..cdaf5fc8d 100644 --- a/e2e/playwright/flow-tests.spec.ts +++ b/e2e/playwright/flow-tests.spec.ts @@ -93,7 +93,7 @@ test('Basic sketch', async ({ page }) => { await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await u.closeDebugPanel() @@ -102,7 +102,7 @@ test('Basic sketch', async ({ page }) => { const startXPx = 600 await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %)`) await page.waitForTimeout(100) @@ -110,20 +110,20 @@ test('Basic sketch', async ({ page }) => { await page.waitForTimeout(100) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %)`) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) |> line([0, ${commonPoints.num1}], %)`) await page.waitForTimeout(100) await page.mouse.click(startXPx, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) |> line([0, ${commonPoints.num1}], %) @@ -149,7 +149,7 @@ test('Basic sketch', async ({ page }) => { await page.getByRole('button', { name: 'Equal Length' }).click() await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %, 'seg01') |> line([0, ${commonPoints.num1}], %) @@ -331,7 +331,7 @@ test('if you click the format button it formats your code', async ({ await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await page.click('.cm-content') - await page.keyboard.type(`const part001 = startSketchOn('XY') + await page.keyboard.type(`const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) @@ -341,7 +341,7 @@ test('if you click the format button it formats your code', async ({ await page.click('button:has-text("Format code")') await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XY') + .toHaveText(`const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) @@ -356,7 +356,7 @@ test('if you use the format keyboard binding it formats your code', async ({ await page.addInitScript(async () => { localStorage.setItem( 'persistCode', - `const part001 = startSketchOn('XY') + `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) @@ -392,7 +392,7 @@ test('if you use the format keyboard binding it formats your code', async ({ await page.keyboard.press('Alt+Shift+KeyF') await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XY') + .toHaveText(`const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) @@ -605,7 +605,7 @@ test('executes on load', async ({ page }) => { await page.addInitScript(async () => { localStorage.setItem( 'persistCode', - `const part001 = startSketchOn('-XZ') + `const sketch001 = startSketchOn('-XZ') |> startProfileAt([-6.95, 4.98], %) |> line([25.1, 0.41], %) |> line([0.73, -14.93], %) @@ -623,16 +623,16 @@ test('executes on load', async ({ page }) => { }) await variablesTabButton.click() - // can find part001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor) - // part001 only shows up in the variables summary if it's been executed + // can find sketch001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor) + // sketch001 only shows up in the variables summary if it's been executed await page.waitForFunction(() => { const variablesElement = document.querySelector( '.pretty-json-container' ) as HTMLDivElement - return variablesElement.innerHTML.includes('part001') + return variablesElement.innerHTML.includes('sketch001') }) await expect( - page.locator('.pretty-json-container >> text=part001') + page.locator('.pretty-json-container >> text=sketch001') ).toBeVisible() }) @@ -698,7 +698,7 @@ const sketchOnPlaneAndBackSideTest = async ( }, } - const code = `const part001 = startSketchOn('${plane}') + const code = `const sketch001 = startSketchOn('${plane}') |> startProfileAt([1.14, -1.54], %)` await u.openDebugPanel() @@ -787,7 +787,7 @@ test('Auto complete works', async ({ page }) => { // and arrowing down to an option await page.click('.cm-content') - await page.keyboard.type('const part001 = start') + await page.keyboard.type('const sketch001 = start') // expect there to be six auto complete options await expect(page.locator('.cm-completionLabel')).toHaveCount(6) @@ -827,7 +827,7 @@ test('Auto complete works', async ({ page }) => { await expect(page.locator('.cm-completionLabel')).not.toBeVisible() await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([3.14, 12], %) |> xLine(5, %) // lin`) }) @@ -1182,28 +1182,28 @@ test('Selections work on fresh and edited sketch', async ({ page }) => { await u.closeDebugPanel() await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %)`) await page.waitForTimeout(100) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %)`) await page.waitForTimeout(100) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) |> line([0, ${commonPoints.num1}], %)`) await page.waitForTimeout(100) await page.mouse.click(startXPx, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) |> line([0, ${commonPoints.num1}], %) @@ -1433,7 +1433,7 @@ test.describe('Command bar tests', () => { localStorage.setItem( 'persistCode', `const distance = sqrt(20) - const part001 = startSketchOn('XZ') + const sketch001 = startSketchOn('XZ') |> startProfileAt([-6.95, 10.98], %) |> line([25.1, 0.41], %) |> line([0.73, -20.93], %) @@ -1503,13 +1503,16 @@ test.describe('Command bar tests', () => { await expect(page.locator('.cm-content')).toHaveText( `const distance = sqrt(20) const distance001 = ${KCL_DEFAULT_LENGTH} -const part001 = startSketchOn('XZ') +const sketch001 = startSketchOn('XZ') |> startProfileAt([-6.95, 10.98], %) |> line([25.1, 0.41], %) |> line([0.73, -20.93], %) |> line([-23.44, 0.52], %) |> close(%) - |> extrude(distance001, %)`.replace(/(\r\n|\n|\r)/gm, '') // remove newlines +const extrude001 = extrude(distance001, sketch001)`.replace( + /(\r\n|\n|\r)/gm, + '' + ) // remove newlines ) }) }) @@ -1538,7 +1541,7 @@ test('Can add multiple sketches', async ({ page }) => { 200 ) - let codeStr = "const part001 = startSketchOn('XY')" + let codeStr = "const sketch001 = startSketchOn('XY')" await page.mouse.click(center.x, viewportSize.height * 0.55) await expectCodeToBe(codeStr) @@ -1576,7 +1579,7 @@ test('Can add multiple sketches', async ({ page }) => { // so selecting the plane again is a bit easier. await page.mouse.click(center.x + 30, center.y) await page.waitForTimeout(500) // TODO detect animation ending, or disable animation - codeStr += "const part002 = startSketchOn('XY')" + codeStr += "const sketch002 = startSketchOn('XY')" await expectCodeToBe(codeStr) await u.closeDebugPanel() @@ -1763,14 +1766,14 @@ test("Various pipe expressions should and shouldn't allow edit and or extrude", |> line([-27.65, -2.78], %) |> close(%) |> extrude(5, %) -const part002 = startSketchOn('XZ') +const sketch002 = startSketchOn('XZ') ${extrudeAndEditAllowed} |> line([10.32, 6.47], %) |> line([9.71, -6.16], %) |> line([-3.08, -9.86], %) |> line([-12.02, -1.54], %) |> close(%) -const part003 = startSketchOn('XZ') +const sketch003 = startSketchOn('XZ') ${editOnly} |> line([27.55, -1.65], %) |> line([4.95, -8], %) @@ -1778,7 +1781,7 @@ const part003 = startSketchOn('XZ') |> line([-15.79, 17.08], %) fn yohey = (pos) => { - const part004 = startSketchOn('XZ') + const sketch004 = startSketchOn('XZ') ${extrudeAndEditBlockedInFunction} |> line([27.55, -1.65], %) |> line([4.95, -10.53], %) @@ -1833,15 +1836,15 @@ fn yohey = (pos) => { page.getByRole('button', { name: 'Edit Sketch' }) ).not.toBeVisible() - // selecting an editable sketch but clicking "start sktech" should start a new sketch and not edit the existing one + // selecting an editable sketch but clicking "start sketch" should start a new sketch and not edit the existing one await page.getByText(selectionsSnippets.extrudeAndEditAllowed).click() await page.getByRole('button', { name: 'Start Sketch' }).click() await page.getByTestId('KCL Code').click() await page.mouse.click(734, 134) await page.getByTestId('KCL Code').click() - // expect main content to contain `part005` i.e. started a new sketch + // expect main content to contain `sketch005` i.e. started a new sketch await expect(page.locator('.cm-content')).toHaveText( - /part005 = startSketchOn\('XZ'\)/ + /sketch001 = startSketchOn\('XZ'\)/ ) }) @@ -1869,7 +1872,7 @@ test('Deselecting line tool should mean nothing happens on click', async ({ await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await page.waitForTimeout(600) @@ -1997,7 +2000,7 @@ test('Can edit segments by dragging their handles', async ({ page }) => { await page.addInitScript(async () => { localStorage.setItem( 'persistCode', - `const part001 = startSketchOn('XZ') + `const sketch001 = startSketchOn('XZ') |> startProfileAt([4.61, -14.01], %) |> line([12.73, -0.09], %) |> tangentialArcTo([24.95, -5.38], %)` @@ -2079,7 +2082,7 @@ test('Can edit segments by dragging their handles', async ({ page }) => { // expect the code to have changed await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([6.44, -12.07], %) |> line([14.72, 1.97], %) |> tangentialArcTo([26.92, -3.32], %)`) @@ -2097,7 +2100,7 @@ const doSnapAtDifferentScales = async ( await u.waitForAuthSkipAppStart() await u.openDebugPanel() - const code = `const part001 = startSketchOn('-XZ') + const code = `const sketch001 = startSketchOn('-XZ') |> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %) |> line([${roundOff(scale * 175.36)}, 0], %) |> line([0, -${roundOff(scale * 175.36) + fudge}], %) @@ -2120,7 +2123,7 @@ const doSnapAtDifferentScales = async ( // select a plane await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('-XZ')` + `const sketch001 = startSketchOn('-XZ')` ) let prevContent = await page.locator('.cm-content').innerText() @@ -2182,7 +2185,7 @@ test('Sketch on face', async ({ page }) => { await page.addInitScript(async () => { localStorage.setItem( 'persistCode', - `const part001 = startSketchOn('XZ') + `const sketch001 = startSketchOn('XZ') |> startProfileAt([3.29, 7.86], %) |> line([2.48, 2.44], %) |> line([2.66, 1.17], %) @@ -2195,7 +2198,7 @@ test('Sketch on face', async ({ page }) => { |> line([-3.86, -2.73], %) |> line([-17.67, 0.85], %) |> close(%) - |> extrude(5 + 7, %)` + const extrude001 = extrude(5 + 7, sketch001)` ) }) @@ -2249,7 +2252,7 @@ test('Sketch on face', async ({ page }) => { previousCodeContent = await page.locator('.cm-content').innerText() await expect(page.locator('.cm-content')) - .toContainText(`const part002 = startSketchOn(part001, 'seg01') + .toContainText(`const sketch002 = startSketchOn(extrude001, 'seg01') |> startProfileAt([-12.94, 6.6], %) |> line([2.45, -0.2], %) |> line([-2.6, -1.25], %) @@ -2288,7 +2291,7 @@ test('Sketch on face', async ({ page }) => { await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) previousCodeContent = await page.locator('.cm-content').innerText() - const result = makeTemplate`const part002 = startSketchOn(part001, 'seg01') + const result = makeTemplate`const sketch002 = startSketchOn(extrude001, 'seg01') |> startProfileAt([-12.83, 6.7], %) |> line([${[2.28, 2.35]}, -${0.07}], %) |> line([-3.05, -1.47], %) @@ -2317,7 +2320,7 @@ test('Sketch on face', async ({ page }) => { await page.keyboard.press('Enter') const result2 = result.genNext` - |> extrude(${[5, 5]} + 7, %)` +const sketch002 = extrude(${[5, 5]} + 7, sketch002)` await expect(page.locator('.cm-content')).toHaveText(result2.regExp) }) @@ -2325,7 +2328,7 @@ test('Can code mod a line length', async ({ page }) => { await page.addInitScript(async () => { localStorage.setItem( 'persistCode', - `const part001 = startSketchOn('XY') + `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) @@ -2363,7 +2366,7 @@ test('Can code mod a line length', async ({ page }) => { await page.getByText('Add constraining value').click() await expect(page.locator('.cm-content')).toHaveText( - `const length001 = 20const part001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %)` + `const length001 = 20const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %)` ) // Make sure we didn't pop out of sketch mode. @@ -2385,7 +2388,7 @@ test('Extrude from command bar selects extrude line after', async ({ await page.addInitScript(async () => { localStorage.setItem( 'persistCode', - `const part001 = startSketchOn('XY') + `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) @@ -2415,7 +2418,7 @@ test('Extrude from command bar selects extrude line after', async ({ await page.keyboard.press('Enter') await page.waitForTimeout(100) await expect(page.locator('.cm-activeLine')).toHaveText( - ` |> extrude(${KCL_DEFAULT_LENGTH}, %)` + `const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)` ) }) @@ -4663,7 +4666,7 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => { await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await u.closeDebugPanel() @@ -4672,7 +4675,7 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => { const startXPx = 600 await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %)`) await page.waitForTimeout(100) @@ -4680,7 +4683,7 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => { await page.waitForTimeout(100) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %)`) @@ -4743,14 +4746,14 @@ test('Engine disconnect & reconnect in sketch mode', async ({ page }) => { // Ensure we can continue sketching await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) |> line([-11.64, 11.11], %)`) await page.waitForTimeout(100) await page.mouse.click(startXPx, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> line([${commonPoints.num1}, 0], %) |> line([-11.64, 11.11], %) diff --git a/e2e/playwright/snapshot-tests.spec.ts b/e2e/playwright/snapshot-tests.spec.ts index 8f32fb688..a590b4c0b 100644 --- a/e2e/playwright/snapshot-tests.spec.ts +++ b/e2e/playwright/snapshot-tests.spec.ts @@ -406,7 +406,7 @@ test('Draft segments should look right', async ({ page, context }) => { await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await page.waitForTimeout(300) // TODO detect animation ending, or disable animation @@ -414,7 +414,7 @@ test('Draft segments should look right', async ({ page, context }) => { const startXPx = 600 await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([9.06, -12.22], %)`) await page.waitForTimeout(100) @@ -428,7 +428,7 @@ test('Draft segments should look right', async ({ page, context }) => { await page.waitForTimeout(100) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([9.06, -12.22], %) |> line([9.14, 0], %)`) @@ -465,7 +465,7 @@ test('Draft rectangles should look right', async ({ page, context }) => { await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await page.waitForTimeout(500) // TODO detect animation ending, or disable animation @@ -514,7 +514,7 @@ test.describe('Client side scene scale should match engine scale', () => { await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await page.waitForTimeout(300) // TODO detect animation ending, or disable animation @@ -522,7 +522,7 @@ test.describe('Client side scene scale should match engine scale', () => { const startXPx = 600 await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([9.06, -12.22], %)`) await page.waitForTimeout(100) @@ -532,7 +532,7 @@ test.describe('Client side scene scale should match engine scale', () => { await page.waitForTimeout(100) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([9.06, -12.22], %) |> line([9.14, 0], %)`) @@ -542,7 +542,7 @@ test.describe('Client side scene scale should match engine scale', () => { await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([9.06, -12.22], %) |> line([9.14, 0], %) |> tangentialArcTo([27.34, -3.08], %)`) @@ -617,7 +617,7 @@ test.describe('Client side scene scale should match engine scale', () => { await page.mouse.click(700, 200) await expect(page.locator('.cm-content')).toHaveText( - `const part001 = startSketchOn('XZ')` + `const sketch001 = startSketchOn('XZ')` ) await page.waitForTimeout(300) // TODO detect animation ending, or disable animation @@ -625,7 +625,7 @@ test.describe('Client side scene scale should match engine scale', () => { const startXPx = 600 await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([230.03, -310.32], %)`) await page.waitForTimeout(100) @@ -635,7 +635,7 @@ test.describe('Client side scene scale should match engine scale', () => { await page.waitForTimeout(100) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([230.03, -310.32], %) |> line([232.2, 0], %)`) @@ -645,7 +645,7 @@ test.describe('Client side scene scale should match engine scale', () => { await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20) await expect(page.locator('.cm-content')) - .toHaveText(`const part001 = startSketchOn('XZ') + .toHaveText(`const sketch001 = startSketchOn('XZ') |> startProfileAt([230.03, -310.32], %) |> line([232.2, 0], %) |> tangentialArcTo([694.43, -78.12], %)`) diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png index 4486e632d..894cfcad0 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-2-Google-Chrome-linux.png index cb6e0a304..3a136fd3f 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-2-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Inch-scale-2-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png index 637a500fc..450db4e99 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png index 00f5f948e..a602d2937 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Client-side-scene-scale-should-match-engine-scale-Millimeter-scale-2-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png index a5fe57b94..2f66e5c89 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-rectangles-should-look-right-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png index 61b51ee99..871dd9b12 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-1-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png index 2f6bf0bd7..f50a2ae44 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Draft-segments-should-look-right-2-Google-Chrome-linux.png differ diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png index 263a6af64..f65abdfe4 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/Sketch-on-face-with-none-z-up-1-Google-Chrome-linux.png differ diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 30efa7e3f..42280f4ef 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -93,7 +93,10 @@ import { createGridHelper, orthoScale, perspScale } from './helpers' import { Models } from '@kittycad/lib' import { uuidv4 } from 'lib/utils' import { SegmentOverlayPayload, SketchDetails } from 'machines/modelingMachine' -import { EngineCommandManager } from 'lang/std/engineConnection' +import { + ArtifactMapCommand, + EngineCommandManager, +} from 'lang/std/engineConnection' import { getRectangleCallExpressions, updateRectangleSketch, @@ -759,14 +762,6 @@ export class SceneEntities { _ast = parse(recast(_ast)) - console.log('onClick', { - sketchInit: sketchInit, - _ast, - x, - y, - truncatedAst, - }) - // Update the primary AST and unequip the rectangle tool await kclManager.executeAstMock(_ast) sceneInfra.modelingSend({ type: 'CancelSketch' }) @@ -1422,6 +1417,30 @@ export class SceneEntities { return ['plane', entity_id] } const artifact = this.engineCommandManager.artifactMap[entity_id] + // If we clicked on an extrude wall, we climb up the parent Id + // to get the sketch profile's face ID. If we clicked on an endcap, + // we already have it. + const targetId = + 'additionalData' in artifact && + artifact.additionalData?.type === 'cap' + ? entity_id + : artifact.parentId + + // tsc cannot infer that target can have extrusions + // from the commandType (why?) so we need to cast it + const target = this.engineCommandManager.artifactMap?.[ + targetId || '' + ] as ArtifactMapCommand & { extrusions?: string[] } + + // TODO: We get the first extrusion command ID, + // which is fine while backend systems only support one extrusion. + // but we need to more robustly handle resolving to the correct extrusion + // if there are multiple. + const extrusions = + this.engineCommandManager.artifactMap?.[ + target?.extrusions?.[0] || '' + ] + if (artifact?.commandType !== 'solid3d_get_extrusion_face_info') return ['other', entity_id] @@ -1429,10 +1448,13 @@ export class SceneEntities { if (!faceInfo?.origin || !faceInfo?.z_axis || !faceInfo?.y_axis) return ['other', entity_id] const { z_axis, y_axis, origin } = faceInfo - const pathToNode = getNodePathFromSourceRange( + const sketchPathToNode = getNodePathFromSourceRange( kclManager.ast, artifact.range ) + const extrudePathToNode = extrusions?.range + ? getNodePathFromSourceRange(kclManager.ast, extrusions.range) + : [] sceneInfra.modelingSend({ type: 'Select default plane', @@ -1443,7 +1465,8 @@ export class SceneEntities { position: [origin.x, origin.y, origin.z].map( (num) => num / sceneInfra._baseUnitMultiplier ) as [number, number, number], - extrudeSegmentPathToNode: pathToNode, + sketchPathToNode, + extrudePathToNode, cap: artifact?.additionalData?.type === 'cap' ? artifact.additionalData.info @@ -1455,7 +1478,6 @@ export class SceneEntities { } const faceResult = await checkExtrudeFaceClick() - console.log('faceResult', faceResult) if (faceResult[0] === 'face') return if (!args || !args.intersects?.[0]) return diff --git a/src/components/ModelingMachineProvider.tsx b/src/components/ModelingMachineProvider.tsx index 5131fba19..8c59c768a 100644 --- a/src/components/ModelingMachineProvider.tsx +++ b/src/components/ModelingMachineProvider.tsx @@ -453,7 +453,8 @@ export const ModelingMachineProvider = ({ const { modifiedAst, pathToNode: pathToNewSketchNode } = sketchOnExtrudedFace( kclManager.ast, - data.extrudeSegmentPathToNode, + data.sketchPathToNode, + data.extrudePathToNode, kclManager.programMemory, data.cap ) diff --git a/src/lang/modifyAst.test.ts b/src/lang/modifyAst.test.ts index 180279440..5ae4811f1 100644 --- a/src/lang/modifyAst.test.ts +++ b/src/lang/modifyAst.test.ts @@ -125,7 +125,7 @@ describe('Testing addSketchTo', () => { 'yz' ) const str = recast(result.modifiedAst) - expect(str).toBe(`const part001 = startSketchOn('YZ') + expect(str).toBe(`const sketch001 = startSketchOn('YZ') |> startProfileAt('default', %) |> line('default', %) `) @@ -291,14 +291,25 @@ describe('testing sketchOnExtrudedFace', () => { |> extrude(5 + 7, %)` const ast = parse(code) const programMemory = await enginelessExecutor(ast) - const snippet = `line([9.7, 9.19], %)` - const range: [number, number] = [ - code.indexOf(snippet), - code.indexOf(snippet) + snippet.length, + const segmentSnippet = `line([9.7, 9.19], %)` + const segmentRange: [number, number] = [ + code.indexOf(segmentSnippet), + code.indexOf(segmentSnippet) + segmentSnippet.length, ] - const pathToNode = getNodePathFromSourceRange(ast, range) + const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange) + const extrudeSnippet = `extrude(5 + 7, %)` + const extrudeRange: [number, number] = [ + code.indexOf(extrudeSnippet), + code.indexOf(extrudeSnippet) + extrudeSnippet.length, + ] + const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange) - const { modifiedAst } = sketchOnExtrudedFace(ast, pathToNode, programMemory) + const { modifiedAst } = sketchOnExtrudedFace( + ast, + segmentPathToNode, + extrudePathToNode, + programMemory + ) const newCode = recast(modifiedAst) expect(newCode).toContain(`const part001 = startSketchOn('-XZ') |> startProfileAt([3.58, 2.06], %) @@ -306,7 +317,7 @@ describe('testing sketchOnExtrudedFace', () => { |> line([8.62, -9.57], %) |> close(%) |> extrude(5 + 7, %) -const part002 = startSketchOn(part001, 'seg01')`) +const sketch001 = startSketchOn(part001, 'seg01')`) }) test('it should be able to extrude on close segments', async () => { const code = `const part001 = startSketchOn('-XZ') @@ -317,14 +328,25 @@ const part002 = startSketchOn(part001, 'seg01')`) |> extrude(5 + 7, %)` const ast = parse(code) const programMemory = await enginelessExecutor(ast) - const snippet = `close(%)` - const range: [number, number] = [ - code.indexOf(snippet), - code.indexOf(snippet) + snippet.length, + const segmentSnippet = `close(%)` + const segmentRange: [number, number] = [ + code.indexOf(segmentSnippet), + code.indexOf(segmentSnippet) + segmentSnippet.length, ] - const pathToNode = getNodePathFromSourceRange(ast, range) + const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange) + const extrudeSnippet = `extrude(5 + 7, %)` + const extrudeRange: [number, number] = [ + code.indexOf(extrudeSnippet), + code.indexOf(extrudeSnippet) + extrudeSnippet.length, + ] + const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange) - const { modifiedAst } = sketchOnExtrudedFace(ast, pathToNode, programMemory) + const { modifiedAst } = sketchOnExtrudedFace( + ast, + segmentPathToNode, + extrudePathToNode, + programMemory + ) const newCode = recast(modifiedAst) expect(newCode).toContain(`const part001 = startSketchOn('-XZ') |> startProfileAt([3.58, 2.06], %) @@ -332,7 +354,7 @@ const part002 = startSketchOn(part001, 'seg01')`) |> line([8.62, -9.57], %) |> close(%, 'seg01') |> extrude(5 + 7, %) -const part002 = startSketchOn(part001, 'seg01')`) +const sketch001 = startSketchOn(part001, 'seg01')`) }) test('it should be able to extrude on start-end caps', async () => { const code = `const part001 = startSketchOn('-XZ') @@ -343,16 +365,23 @@ const part002 = startSketchOn(part001, 'seg01')`) |> extrude(5 + 7, %)` const ast = parse(code) const programMemory = await enginelessExecutor(ast) - const snippet = `startProfileAt([3.58, 2.06], %)` - const range: [number, number] = [ - code.indexOf(snippet), - code.indexOf(snippet) + snippet.length, + const sketchSnippet = `startProfileAt([3.58, 2.06], %)` + const sketchRange: [number, number] = [ + code.indexOf(sketchSnippet), + code.indexOf(sketchSnippet) + sketchSnippet.length, ] - const pathToNode = getNodePathFromSourceRange(ast, range) + const sketchPathToNode = getNodePathFromSourceRange(ast, sketchRange) + const extrudeSnippet = `extrude(5 + 7, %)` + const extrudeRange: [number, number] = [ + code.indexOf(extrudeSnippet), + code.indexOf(extrudeSnippet) + extrudeSnippet.length, + ] + const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange) const { modifiedAst } = sketchOnExtrudedFace( ast, - pathToNode, + sketchPathToNode, + extrudePathToNode, programMemory, 'end' ) @@ -363,7 +392,47 @@ const part002 = startSketchOn(part001, 'seg01')`) |> line([8.62, -9.57], %) |> close(%) |> extrude(5 + 7, %) -const part002 = startSketchOn(part001, 'END')`) +const sketch001 = startSketchOn(part001, 'END')`) + }) + test('it should ensure that the new sketch is inserted after the extrude', async () => { + const code = `const sketch001 = startSketchOn('-XZ') + |> startProfileAt([3.29, 7.86], %) + |> line([2.48, 2.44], %) + |> line([2.66, 1.17], %) + |> line([3.75, 0.46], %) + |> line([4.99, -0.46], %) + |> line([3.3, -2.12], %) + |> line([2.16, -3.33], %) + |> line([0.85, -3.08], %) + |> line([-0.18, -3.36], %) + |> line([-3.86, -2.73], %) + |> line([-17.67, 0.85], %) + |> close(%) + const part001 = extrude(5 + 7, sketch001)` + const ast = parse(code) + const programMemory = await enginelessExecutor(ast) + const segmentSnippet = `line([4.99, -0.46], %)` + const segmentRange: [number, number] = [ + code.indexOf(segmentSnippet), + code.indexOf(segmentSnippet) + segmentSnippet.length, + ] + const segmentPathToNode = getNodePathFromSourceRange(ast, segmentRange) + const extrudeSnippet = `extrude(5 + 7, sketch001)` + const extrudeRange: [number, number] = [ + code.indexOf(extrudeSnippet), + code.indexOf(extrudeSnippet) + extrudeSnippet.length, + ] + const extrudePathToNode = getNodePathFromSourceRange(ast, extrudeRange) + + const { modifiedAst } = sketchOnExtrudedFace( + ast, + segmentPathToNode, + extrudePathToNode, + programMemory + ) + const newCode = recast(modifiedAst) + expect(newCode).toContain(`const part001 = extrude(5 + 7, sketch001) +const sketch002 = startSketchOn(part001, 'seg01')`) }) }) diff --git a/src/lang/modifyAst.ts b/src/lang/modifyAst.ts index 21da7f6a0..10be1300f 100644 --- a/src/lang/modifyAst.ts +++ b/src/lang/modifyAst.ts @@ -34,6 +34,7 @@ import { } from './std/sketchcombos' import { DefaultPlaneStr } from 'clientSideScene/sceneEntities' import { isOverlap, roundOff } from 'lib/utils' +import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants' import { ConstrainInfo } from './std/stdTypes' export function startSketchOnDefault( @@ -42,7 +43,8 @@ export function startSketchOnDefault( name = '' ): { modifiedAst: Program; id: string; pathToNode: PathToNode } { const _node = { ...node } - const _name = name || findUniqueName(node, 'part') + const _name = + name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH) const startSketchOn = createCallExpressionStdLib('startSketchOn', [ createLiteral(axis), @@ -109,7 +111,8 @@ export function addSketchTo( name = '' ): { modifiedAst: Program; id: string; pathToNode: PathToNode } { const _node = { ...node } - const _name = name || findUniqueName(node, 'part') + const _name = + name || findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH) const startSketchOn = createCallExpressionStdLib('startSketchOn', [ createLiteral(axis.toUpperCase()), @@ -242,7 +245,7 @@ export function mutateObjExpProp( export function extrudeSketch( node: Program, pathToNode: PathToNode, - shouldPipe = true, + shouldPipe = false, distance = createLiteral(4) as Value ): { modifiedAst: Program @@ -293,12 +296,22 @@ export function extrudeSketch( pathToExtrudeArg, } } - const name = findUniqueName(node, 'part') + + // We're not creating a pipe expression, + // but rather a separate constant for the extrusion + const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.EXTRUDE) const VariableDeclaration = createVariableDeclaration(name, extrudeCall) - _node.body.splice(_node.body.length, 0, VariableDeclaration) + + const sketchIndexInPathToNode = + pathToDecleration.findIndex((a) => a[0] === 'body') + 1 + const sketchIndexInBody = pathToDecleration[ + sketchIndexInPathToNode + ][0] as number + _node.body.splice(sketchIndexInBody + 1, 0, VariableDeclaration) + const pathToExtrudeArg: PathToNode = [ ['body', ''], - [_node.body.length, 'index'], + [sketchIndexInBody + 1, 'index'], ['declarations', 'VariableDeclaration'], [0, 'index'], ['init', 'VariableDeclarator'], @@ -306,7 +319,7 @@ export function extrudeSketch( [0, 'index'], ] return { - modifiedAst: node, + modifiedAst: _node, pathToNode: [...pathToNode.slice(0, -1), [-1, 'index']], pathToExtrudeArg, } @@ -314,31 +327,41 @@ export function extrudeSketch( export function sketchOnExtrudedFace( node: Program, - pathToNode: PathToNode, + sketchPathToNode: PathToNode, + extrudePathToNode: PathToNode, programMemory: ProgramMemory, cap: 'none' | 'start' | 'end' = 'none' ): { modifiedAst: Program; pathToNode: PathToNode } { let _node = { ...node } - const newSketchName = findUniqueName(node, 'part') + const newSketchName = findUniqueName( + node, + KCL_DEFAULT_CONSTANT_PREFIXES.SKETCH + ) const { node: oldSketchNode } = getNodeFromPath( _node, - pathToNode, + sketchPathToNode, 'VariableDeclarator', true ) const oldSketchName = oldSketchNode.id.name const { node: expression } = getNodeFromPath( _node, - pathToNode, + sketchPathToNode, 'CallExpression' ) + const { node: extrudeVarDec } = getNodeFromPath( + _node, + extrudePathToNode, + 'VariableDeclarator' + ) + const extrudeName = extrudeVarDec.id?.name let _tag = '' if (cap === 'none') { const { modifiedAst, tag } = addTagForSketchOnFace( { previousProgramMemory: programMemory, - pathToNode, + pathToNode: sketchPathToNode, node: _node, }, expression.callee.name @@ -352,13 +375,16 @@ export function sketchOnExtrudedFace( const newSketch = createVariableDeclaration( newSketchName, createCallExpressionStdLib('startSketchOn', [ - createIdentifier(oldSketchName), + createIdentifier(extrudeName ? extrudeName : oldSketchName), createLiteral(_tag), ]), 'const' ) - const expressionIndex = pathToNode[1][0] as number + const expressionIndex = Math.max( + sketchPathToNode[1][0] as number, + extrudePathToNode[1][0] as number + ) _node.body.splice(expressionIndex + 1, 0, newSketch) const newpathToNode: PathToNode = [ ['body', ''], diff --git a/src/lang/std/engineConnection.ts b/src/lang/std/engineConnection.ts index 02a01a5c6..1ead668b4 100644 --- a/src/lang/std/engineConnection.ts +++ b/src/lang/std/engineConnection.ts @@ -12,22 +12,43 @@ let lastMessage = '' // TODO(paultag): This ought to be tweakable. const pingIntervalMs = 10000 -interface CommandInfo { - commandType: CommandTypes - range: SourceRange - pathToNode: PathToNode - parentId?: string - additionalData?: - | { - type: 'cap' - info: 'start' | 'end' - } - | { - type: 'batch-ids' - ids: string[] - info?: null - } -} +type CommandTypes = Models['ModelingCmd_type']['type'] | 'batch' + +type CommandInfo = + | { + commandType: 'extrude' + // commandType: CommandTypes + range: SourceRange + pathToNode: PathToNode + /// uuid of the entity to extrude + target: string + parentId?: string + } + | { + commandType: 'start_path' + // commandType: CommandTypes + range: SourceRange + pathToNode: PathToNode + /// uuid of the entity that have been extruded + extrusions: string[] + parentId?: string + } + | { + commandType: CommandTypes + range: SourceRange + pathToNode: PathToNode + parentId?: string + additionalData?: + | { + type: 'cap' + info: 'start' | 'end' + } + | { + type: 'batch-ids' + ids: string[] + info?: null + } + } function isHighlightSetEntity_type( data: any @@ -38,13 +59,13 @@ function isHighlightSetEntity_type( type WebSocketResponse = Models['WebSocketResponse_type'] type OkWebSocketResponseData = Models['OkWebSocketResponseData_type'] -interface ResultCommand extends CommandInfo { +type ResultCommand = CommandInfo & { type: 'result' data: any raw: WebSocketResponse headVertexId?: string } -interface FailedCommand extends CommandInfo { +type FailedCommand = CommandInfo & { type: 'failed' errors: Models['FailureWebSocketResponse_type']['errors'] } @@ -57,12 +78,14 @@ interface ResolveCommand { data?: Models['OkModelingCmdResponse_type'] errors?: Models['FailureWebSocketResponse_type']['errors'] } -interface PendingCommand extends CommandInfo { +type PendingCommand = CommandInfo & { type: 'pending' promise: Promise resolve: (val: ResolveCommand) => void } +export type ArtifactMapCommand = ResultCommand | PendingCommand | FailedCommand + /** * The ArtifactMap is a client-side representation of the artifacts that * have been sent to the server-side engine. It is used to keep track of @@ -72,7 +95,7 @@ interface PendingCommand extends CommandInfo { * lines of KCL code that generated them. */ export interface ArtifactMap { - [commandId: string]: ResultCommand | PendingCommand | FailedCommand + [commandId: string]: ArtifactMapCommand } interface NewTrackArgs { @@ -988,8 +1011,6 @@ class EngineConnection extends EventTarget { export type EngineCommand = Models['WebSocketRequest_type'] type ModelTypes = Models['OkModelingCmdResponse_type']['type'] -type CommandTypes = Models['ModelingCmd_type']['type'] | 'batch' - type UnreliableResponses = Extract< Models['OkModelingCmdResponse_type'], { type: 'highlight_set_entity' | 'camera_drag_move' } @@ -1814,9 +1835,12 @@ export class EngineCommandManager extends EventTarget { if (command.type === 'solid3d_get_extrusion_face_info') { const edgeArtifact = this.artifactMap[command.edge_id] // edges's parent id is to the original "start_path" artifact - if (edgeArtifact?.parentId) return edgeArtifact.parentId + if (edgeArtifact && edgeArtifact.parentId) { + return edgeArtifact.parentId + } } if (command.type === 'close_path') return command.path_id + if (command.type === 'extrude') return command.target // handle other commands that have a parent here } const pathToNode = ast @@ -1831,6 +1855,33 @@ export class EngineCommandManager extends EventTarget { promise, resolve, } + if (command.type === 'extrude') { + this.artifactMap[id] = { + range: range || [0, 0], + pathToNode, + type: 'pending', + commandType: 'extrude', + parentId: getParentId(), + promise, + target: command.target, + resolve, + } + const target = this.artifactMap[command.target] + if (target.commandType === 'start_path') { + // tsc cannot infer that target can have extrusions + // from the commandType (why?) so we need to cast it + const typedTarget = target as ( + | PendingCommand + | ResultCommand + | FailedCommand + ) & { extrusions?: string[] } + if (typedTarget?.extrusions?.length) { + typedTarget.extrusions.push(id) + } else { + typedTarget.extrusions = [id] + } + } + } return promise } async handlePendingBatchCommand( diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 14ca4aafa..0e4c8ab19 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -44,5 +44,13 @@ export const RELEVANT_FILE_TYPES = [ ] as const /** The default name for a tutorial project */ export const ONBOARDING_PROJECT_NAME = 'Tutorial Project $nn' +/** + * The default starting constant name for various modeling operations. + * These are used to generate unique names for new objects. + * */ +export const KCL_DEFAULT_CONSTANT_PREFIXES = { + SKETCH: 'sketch', + EXTRUDE: 'extrude', +} as const /** The default KCL length expression */ export const KCL_DEFAULT_LENGTH = `5` diff --git a/src/machines/modelingMachine.ts b/src/machines/modelingMachine.ts index 852e21911..17a1c66e7 100644 --- a/src/machines/modelingMachine.ts +++ b/src/machines/modelingMachine.ts @@ -145,7 +145,8 @@ export type ModelingMachineEvent = | { type: 'extrudeFace' position: [number, number, number] - extrudeSegmentPathToNode: PathToNode + sketchPathToNode: PathToNode + extrudePathToNode: PathToNode cap: 'start' | 'end' | 'none' faceId: string } @@ -883,7 +884,7 @@ export const modelingMachine = createMachine( const { modifiedAst, pathToExtrudeArg } = extrudeSketch( ast, pathToNode, - true, + false, 'variableName' in distance ? distance.variableIdentifierAst : distance.valueAst