Compare commits
5 Commits
pierremtb/
...
remove-the
Author | SHA1 | Date | |
---|---|---|---|
f46edcddf3 | |||
68fd921a64 | |||
a20e710e8f | |||
9daf2d7794 | |||
f86473d13b |
@ -1214,12 +1214,18 @@ test('Auto complete works', async ({ page }) => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
// press arrow down twice then enter to accept xLine
|
// press arrow down twice then enter to accept xLine
|
||||||
await page.keyboard.press('ArrowDown')
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.press('ArrowDown')
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.press('Enter')
|
await page.keyboard.press('Enter')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
// finish line with comment
|
// finish line with comment
|
||||||
await page.keyboard.type('5')
|
await page.keyboard.type('5')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.press('Tab')
|
await page.keyboard.press('Tab')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.press('Tab')
|
await page.keyboard.press('Tab')
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.keyboard.type(' // lin')
|
await page.keyboard.type(' // lin')
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
// there shouldn't be any auto complete options for 'lin' in the comment
|
// there shouldn't be any auto complete options for 'lin' in the comment
|
||||||
@ -1689,6 +1695,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test.describe('Testing selections', () => {
|
test.describe('Testing selections', () => {
|
||||||
|
test.setTimeout(90_000)
|
||||||
test('Selections work on fresh and edited sketch', async ({ page }) => {
|
test('Selections work on fresh and edited sketch', async ({ page }) => {
|
||||||
// tests mapping works on fresh sketch and edited sketch
|
// tests mapping works on fresh sketch and edited sketch
|
||||||
// tests using hovers which is the same as selections, because if
|
// tests using hovers which is the same as selections, because if
|
||||||
@ -1894,6 +1901,239 @@ test.describe('Testing selections', () => {
|
|||||||
await selectionSequence()
|
await selectionSequence()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Solids should be select and deletable', async ({ page }) => {
|
||||||
|
test.setTimeout(90_000)
|
||||||
|
const u = await getUtils(page)
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([-79.26, 95.04], %)
|
||||||
|
|> line([112.54, 127.64], %, $seg02)
|
||||||
|
|> line([170.36, -121.61], %, $seg01)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
const sketch005 = startSketchOn(extrude001, 'END')
|
||||||
|
|> startProfileAt([23.24, 136.52], %)
|
||||||
|
|> line([-8.44, 36.61], %)
|
||||||
|
|> line([49.4, 2.05], %)
|
||||||
|
|> line([29.69, -46.95], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const sketch003 = startSketchOn(extrude001, seg01)
|
||||||
|
|> startProfileAt([21.23, 17.81], %)
|
||||||
|
|> line([51.97, 21.32], %)
|
||||||
|
|> line([4.07, -22.75], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const sketch002 = startSketchOn(extrude001, seg02)
|
||||||
|
|> startProfileAt([-100.54, 16.99], %)
|
||||||
|
|> line([0, 20.03], %)
|
||||||
|
|> line([62.61, 0], %, $seg03)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude002 = extrude(50, sketch002)
|
||||||
|
const sketch004 = startSketchOn(extrude002, seg03)
|
||||||
|
|> startProfileAt([57.07, 134.77], %)
|
||||||
|
|> line([-4.72, 22.84], %)
|
||||||
|
|> line([28.8, 6.71], %)
|
||||||
|
|> line([9.19, -25.33], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude003 = extrude(20, sketch004)
|
||||||
|
const pipeLength = 40
|
||||||
|
const pipeSmallDia = 10
|
||||||
|
const pipeLargeDia = 20
|
||||||
|
const thickness = 0.5
|
||||||
|
const part009 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([pipeLargeDia - (thickness / 2), 38], %)
|
||||||
|
|> line([thickness, 0], %)
|
||||||
|
|> line([0, -1], %)
|
||||||
|
|> angledLineToX({
|
||||||
|
angle: 60,
|
||||||
|
to: pipeSmallDia + thickness
|
||||||
|
}, %)
|
||||||
|
|> line([0, -pipeLength], %)
|
||||||
|
|> angledLineToX({
|
||||||
|
angle: -60,
|
||||||
|
to: pipeLargeDia + thickness
|
||||||
|
}, %)
|
||||||
|
|> line([0, -1], %)
|
||||||
|
|> line([-thickness, 0], %)
|
||||||
|
|> line([0, 1], %)
|
||||||
|
|> angledLineToX({ angle: 120, to: pipeSmallDia }, %)
|
||||||
|
|> line([0, pipeLength], %)
|
||||||
|
|> angledLineToX({ angle: 60, to: pipeLargeDia }, %)
|
||||||
|
|> close(%)
|
||||||
|
const rev = revolve({ axis: 'y' }, part009)
|
||||||
|
`
|
||||||
|
)
|
||||||
|
}, KCL_DEFAULT_LENGTH)
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
|
||||||
|
await u.openDebugPanel()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
await u.openAndClearDebugPanel()
|
||||||
|
await u.sendCustomCmd({
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: uuidv4(),
|
||||||
|
cmd: {
|
||||||
|
type: 'default_camera_look_at',
|
||||||
|
vantage: { x: 1139.49, y: -7053, z: 8597.31 },
|
||||||
|
center: { x: -2206.68, y: -1298.36, z: 60 },
|
||||||
|
up: { x: 0, y: 0, z: 1 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await u.sendCustomCmd({
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: uuidv4(),
|
||||||
|
cmd: {
|
||||||
|
type: 'default_camera_get_settings',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
|
const revolve = { x: 646, y: 248 }
|
||||||
|
const parentExtrude = { x: 915, y: 133 }
|
||||||
|
const solid2d = { x: 770, y: 167 }
|
||||||
|
|
||||||
|
// DELETE REVOLVE
|
||||||
|
await page.mouse.click(revolve.x, revolve.y)
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-activeLine')).toHaveText(
|
||||||
|
'|> line([0, -pipeLength], %)'
|
||||||
|
)
|
||||||
|
await u.clearCommandLogs()
|
||||||
|
await page.keyboard.press('Backspace')
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
|
await expect(u.codeLocator).not.toContainText(
|
||||||
|
`const rev = revolve({ axis: 'y' }, part009)`
|
||||||
|
)
|
||||||
|
|
||||||
|
// DELETE PARENT EXTRUDE
|
||||||
|
await page.mouse.click(parentExtrude.x, parentExtrude.y)
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-activeLine')).toHaveText(
|
||||||
|
'|> line([170.36, -121.61], %, $seg01)'
|
||||||
|
)
|
||||||
|
await u.clearCommandLogs()
|
||||||
|
await page.keyboard.press('Backspace')
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
await expect(u.codeLocator).not.toContainText(
|
||||||
|
`const extrude001 = extrude(50, sketch001)`
|
||||||
|
)
|
||||||
|
await expect(u.codeLocator).toContainText(`const sketch005 = startSketchOn({
|
||||||
|
plane: {
|
||||||
|
origin: { x: 0, y: -50, z: 0 },
|
||||||
|
x_axis: { x: 1, y: 0, z: 0 },
|
||||||
|
y_axis: { x: 0, y: 0, z: 1 },
|
||||||
|
z_axis: { x: 0, y: -1, z: 0 }
|
||||||
|
}
|
||||||
|
})`)
|
||||||
|
await expect(u.codeLocator).toContainText(`const sketch003 = startSketchOn({
|
||||||
|
plane: {
|
||||||
|
origin: { x: 116.53, y: 0, z: 163.25 },
|
||||||
|
x_axis: { x: -0.81, y: 0, z: 0.58 },
|
||||||
|
y_axis: { x: 0, y: -1, z: 0 },
|
||||||
|
z_axis: { x: 0.58, y: 0, z: 0.81 }
|
||||||
|
}
|
||||||
|
})`)
|
||||||
|
await expect(u.codeLocator).toContainText(`const sketch002 = startSketchOn({
|
||||||
|
plane: {
|
||||||
|
origin: { x: -91.74, y: 0, z: 80.89 },
|
||||||
|
x_axis: { x: -0.66, y: 0, z: -0.75 },
|
||||||
|
y_axis: { x: 0, y: -1, z: 0 },
|
||||||
|
z_axis: { x: -0.75, y: 0, z: 0.66 }
|
||||||
|
}
|
||||||
|
})`)
|
||||||
|
|
||||||
|
// DELETE SOLID 2D
|
||||||
|
await page.mouse.click(solid2d.x, solid2d.y)
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-activeLine')).toHaveText(
|
||||||
|
'|> startProfileAt([23.24, 136.52], %)'
|
||||||
|
)
|
||||||
|
await u.clearCommandLogs()
|
||||||
|
await page.keyboard.press('Backspace')
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
await expect(u.codeLocator).not.toContainText(
|
||||||
|
`const sketch005 = startSketchOn({`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
test("Deleting solid that the AST mod can't handle results in a toast message", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const u = await getUtils(page)
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([-79.26, 95.04], %)
|
||||||
|
|> line([112.54, 127.64], %, $seg02)
|
||||||
|
|> line([170.36, -121.61], %, $seg01)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(50, sketch001)
|
||||||
|
const launderExtrudeThroughVar = extrude001
|
||||||
|
const sketch002 = startSketchOn(launderExtrudeThroughVar, seg02)
|
||||||
|
|> startProfileAt([-100.54, 16.99], %)
|
||||||
|
|> line([0, 20.03], %)
|
||||||
|
|> line([62.61, 0], %, $seg03)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
`
|
||||||
|
)
|
||||||
|
}, KCL_DEFAULT_LENGTH)
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
|
||||||
|
await u.openDebugPanel()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
await u.openAndClearDebugPanel()
|
||||||
|
await u.sendCustomCmd({
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: uuidv4(),
|
||||||
|
cmd: {
|
||||||
|
type: 'default_camera_look_at',
|
||||||
|
vantage: { x: 1139.49, y: -7053, z: 8597.31 },
|
||||||
|
center: { x: -2206.68, y: -1298.36, z: 60 },
|
||||||
|
up: { x: 0, y: 0, z: 1 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await u.sendCustomCmd({
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: uuidv4(),
|
||||||
|
cmd: {
|
||||||
|
type: 'default_camera_get_settings',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
|
||||||
|
// attempt delete
|
||||||
|
await page.mouse.click(930, 139)
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.locator('.cm-activeLine')).toHaveText(
|
||||||
|
'|> line([170.36, -121.61], %, $seg01)'
|
||||||
|
)
|
||||||
|
await u.clearCommandLogs()
|
||||||
|
await page.keyboard.press('Backspace')
|
||||||
|
|
||||||
|
await expect(page.getByText('Unable to delete part')).toBeVisible()
|
||||||
|
})
|
||||||
test('Hovering over 3d features highlights code', async ({ page }) => {
|
test('Hovering over 3d features highlights code', async ({ page }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
|
await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
|
||||||
@ -2654,6 +2894,7 @@ fn yohey = (pos) => {
|
|||||||
// selecting an editable sketch but clicking "start sketch" 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.getByText(selectionsSnippets.extrudeAndEditAllowed).click()
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
await page.getByTestId('KCL Code').click()
|
await page.getByTestId('KCL Code').click()
|
||||||
await page.waitForTimeout(200)
|
await page.waitForTimeout(200)
|
||||||
await page.mouse.click(734, 134)
|
await page.mouse.click(734, 134)
|
||||||
@ -3278,6 +3519,7 @@ test.describe('Snap to close works (at any scale)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('Sketch on face', async ({ page }) => {
|
test('Sketch on face', async ({ page }) => {
|
||||||
|
test.setTimeout(90_000)
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
@ -5471,6 +5713,7 @@ ${extraLine ? 'const myVar = segLen(seg01, part001)' : ''}`
|
|||||||
)
|
)
|
||||||
|
|
||||||
await page.getByTestId('overlay-menu').click()
|
await page.getByTestId('overlay-menu').click()
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.getByText('Delete Segment').click()
|
await page.getByText('Delete Segment').click()
|
||||||
|
|
||||||
await page.getByText('Cancel').click()
|
await page.getByText('Cancel').click()
|
||||||
@ -5483,6 +5726,7 @@ ${extraLine ? 'const myVar = segLen(seg01, part001)' : ''}`
|
|||||||
)
|
)
|
||||||
|
|
||||||
await page.getByTestId('overlay-menu').click()
|
await page.getByTestId('overlay-menu').click()
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.getByText('Delete Segment').click()
|
await page.getByText('Delete Segment').click()
|
||||||
|
|
||||||
await page.getByText('Continue and unconstrain').last().click()
|
await page.getByText('Continue and unconstrain').last().click()
|
||||||
@ -5631,6 +5875,7 @@ ${extraLine ? 'const myVar = segLen(seg01, part001)' : ''}`
|
|||||||
await expect(page.locator('.cm-content')).toContainText(before)
|
await expect(page.locator('.cm-content')).toContainText(before)
|
||||||
|
|
||||||
await page.getByTestId('overlay-menu').click()
|
await page.getByTestId('overlay-menu').click()
|
||||||
|
await page.waitForTimeout(100)
|
||||||
await page.getByText('Remove constraints').click()
|
await page.getByText('Remove constraints').click()
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toContainText(after)
|
await expect(page.locator('.cm-content')).toContainText(after)
|
||||||
|
@ -45,8 +45,8 @@ async function clearCommandLogs(page: Page) {
|
|||||||
await page.getByTestId('clear-commands').click()
|
await page.getByTestId('clear-commands').click()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function expectCmdLog(page: Page, locatorStr: string) {
|
async function expectCmdLog(page: Page, locatorStr: string, timeout = 5000) {
|
||||||
await expect(page.locator(locatorStr).last()).toBeVisible()
|
await expect(page.locator(locatorStr).last()).toBeVisible({ timeout })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitForDefaultPlanesToBeVisible(page: Page) {
|
async function waitForDefaultPlanesToBeVisible(page: Page) {
|
||||||
@ -228,7 +228,8 @@ export async function getUtils(page: Page) {
|
|||||||
await fillInput('z', xyz[2])
|
await fillInput('z', xyz[2])
|
||||||
},
|
},
|
||||||
clearCommandLogs: () => clearCommandLogs(page),
|
clearCommandLogs: () => clearCommandLogs(page),
|
||||||
expectCmdLog: (locatorStr: string) => expectCmdLog(page, locatorStr),
|
expectCmdLog: (locatorStr: string, timeout = 5000) =>
|
||||||
|
expectCmdLog(page, locatorStr, timeout),
|
||||||
openKclCodePanel: () => openKclCodePanel(page),
|
openKclCodePanel: () => openKclCodePanel(page),
|
||||||
closeKclCodePanel: () => closeKclCodePanel(page),
|
closeKclCodePanel: () => closeKclCodePanel(page),
|
||||||
openDebugPanel: () => openDebugPanel(page),
|
openDebugPanel: () => openDebugPanel(page),
|
||||||
|
4
src-tauri/Cargo.lock
generated
4
src-tauri/Cargo.lock
generated
@ -4546,9 +4546,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.116"
|
version = "1.0.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"itoa 1.0.11",
|
"itoa 1.0.11",
|
||||||
|
@ -25,6 +25,7 @@ import { LowerRightControls } from 'components/LowerRightControls'
|
|||||||
import ModalContainer from 'react-modal-promise'
|
import ModalContainer from 'react-modal-promise'
|
||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||||
import Gizmo from 'components/Gizmo'
|
import Gizmo from 'components/Gizmo'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useRefreshSettings(paths.FILE + 'SETTINGS')
|
useRefreshSettings(paths.FILE + 'SETTINGS')
|
||||||
@ -55,7 +56,11 @@ export function App() {
|
|||||||
setHtmlRef(ref)
|
setHtmlRef(ref)
|
||||||
}, [ref])
|
}, [ref])
|
||||||
|
|
||||||
const { settings } = useSettingsAuthContext()
|
const { auth, settings } = useSettingsAuthContext()
|
||||||
|
const token = auth?.context?.token
|
||||||
|
|
||||||
|
const coreDumpManager = new CoreDumpManager(engineCommandManager, ref, token)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
app: { onboardingStatus },
|
app: { onboardingStatus },
|
||||||
} = settings.context
|
} = settings.context
|
||||||
@ -129,7 +134,7 @@ export function App() {
|
|||||||
<ModelingSidebar paneOpacity={paneOpacity} />
|
<ModelingSidebar paneOpacity={paneOpacity} />
|
||||||
<Stream />
|
<Stream />
|
||||||
{/* <CamToggle /> */}
|
{/* <CamToggle /> */}
|
||||||
<LowerRightControls>
|
<LowerRightControls coreDumpManager={coreDumpManager}>
|
||||||
<Gizmo />
|
<Gizmo />
|
||||||
</LowerRightControls>
|
</LowerRightControls>
|
||||||
</div>
|
</div>
|
||||||
|
@ -534,7 +534,7 @@ export class SceneEntities {
|
|||||||
segmentName: 'line' | 'tangentialArcTo' = 'line',
|
segmentName: 'line' | 'tangentialArcTo' = 'line',
|
||||||
shouldTearDown = true
|
shouldTearDown = true
|
||||||
) => {
|
) => {
|
||||||
const _ast = JSON.parse(JSON.stringify(kclManager.ast))
|
const _ast = kclManager.ast
|
||||||
|
|
||||||
const _node1 = getNodeFromPath<VariableDeclaration>(
|
const _node1 = getNodeFromPath<VariableDeclaration>(
|
||||||
_ast,
|
_ast,
|
||||||
@ -692,7 +692,7 @@ export class SceneEntities {
|
|||||||
sketchOrigin: [number, number, number],
|
sketchOrigin: [number, number, number],
|
||||||
rectangleOrigin: [x: number, y: number]
|
rectangleOrigin: [x: number, y: number]
|
||||||
) => {
|
) => {
|
||||||
let _ast = JSON.parse(JSON.stringify(kclManager.ast))
|
let _ast = kclManager.ast
|
||||||
|
|
||||||
const _node1 = getNodeFromPath<VariableDeclaration>(
|
const _node1 = getNodeFromPath<VariableDeclaration>(
|
||||||
_ast,
|
_ast,
|
||||||
@ -723,7 +723,9 @@ export class SceneEntities {
|
|||||||
...getRectangleCallExpressions(rectangleOrigin, tags),
|
...getRectangleCallExpressions(rectangleOrigin, tags),
|
||||||
])
|
])
|
||||||
|
|
||||||
_ast = parse(recast(_ast))
|
let result = parse(recast(_ast))
|
||||||
|
if (trap(result)) return Promise.reject(result)
|
||||||
|
_ast = result
|
||||||
|
|
||||||
const { programMemoryOverride, truncatedAst } = await this.setupSketch({
|
const { programMemoryOverride, truncatedAst } = await this.setupSketch({
|
||||||
sketchPathToNode,
|
sketchPathToNode,
|
||||||
@ -737,7 +739,7 @@ export class SceneEntities {
|
|||||||
sceneInfra.setCallbacks({
|
sceneInfra.setCallbacks({
|
||||||
onMove: async (args) => {
|
onMove: async (args) => {
|
||||||
// Update the width and height of the draft rectangle
|
// Update the width and height of the draft rectangle
|
||||||
const pathToNodeTwo = JSON.parse(JSON.stringify(sketchPathToNode))
|
const pathToNodeTwo = sketchPathToNode
|
||||||
pathToNodeTwo[1][0] = 0
|
pathToNodeTwo[1][0] = 0
|
||||||
|
|
||||||
const _node = getNodeFromPath<VariableDeclaration>(
|
const _node = getNodeFromPath<VariableDeclaration>(
|
||||||
@ -799,7 +801,9 @@ export class SceneEntities {
|
|||||||
if (sketchInit.type === 'PipeExpression') {
|
if (sketchInit.type === 'PipeExpression') {
|
||||||
updateRectangleSketch(sketchInit, x, y, tags[0])
|
updateRectangleSketch(sketchInit, x, y, tags[0])
|
||||||
|
|
||||||
_ast = parse(recast(_ast))
|
let result = parse(recast(_ast))
|
||||||
|
if (trap(result)) return Promise.reject(result)
|
||||||
|
_ast = result
|
||||||
|
|
||||||
// Update the primary AST and unequip the rectangle tool
|
// Update the primary AST and unequip the rectangle tool
|
||||||
await kclManager.executeAstMock(_ast)
|
await kclManager.executeAstMock(_ast)
|
||||||
@ -1003,10 +1007,8 @@ export class SceneEntities {
|
|||||||
PROFILE_START,
|
PROFILE_START,
|
||||||
])
|
])
|
||||||
if (!group) return
|
if (!group) return
|
||||||
const pathToNode: PathToNode = JSON.parse(
|
const pathToNode: PathToNode = group.userData.pathToNode
|
||||||
JSON.stringify(group.userData.pathToNode)
|
const varDecIndex: number = pathToNode[1][0] as number
|
||||||
)
|
|
||||||
const varDecIndex = JSON.parse(JSON.stringify(pathToNode[1][0]))
|
|
||||||
if (draftInfo) {
|
if (draftInfo) {
|
||||||
pathToNode[1][0] = 0
|
pathToNode[1][0] = 0
|
||||||
}
|
}
|
||||||
@ -1719,7 +1721,7 @@ function prepareTruncatedMemoryAndAst(
|
|||||||
}
|
}
|
||||||
| Error {
|
| Error {
|
||||||
const bodyIndex = Number(sketchPathToNode?.[1]?.[0]) || 0
|
const bodyIndex = Number(sketchPathToNode?.[1]?.[0]) || 0
|
||||||
const _ast = JSON.parse(JSON.stringify(ast))
|
const _ast = ast
|
||||||
|
|
||||||
const _node = getNodeFromPath<VariableDeclaration>(
|
const _node = getNodeFromPath<VariableDeclaration>(
|
||||||
_ast,
|
_ast,
|
||||||
@ -1778,7 +1780,7 @@ function prepareTruncatedMemoryAndAst(
|
|||||||
}
|
}
|
||||||
const truncatedAst: Program = {
|
const truncatedAst: Program = {
|
||||||
..._ast,
|
..._ast,
|
||||||
body: [JSON.parse(JSON.stringify(_ast.body[bodyIndex]))],
|
body: [_ast.body[bodyIndex]],
|
||||||
}
|
}
|
||||||
const programMemoryOverride = programMemoryInit()
|
const programMemoryOverride = programMemoryInit()
|
||||||
if (err(programMemoryOverride)) return programMemoryOverride
|
if (err(programMemoryOverride)) return programMemoryOverride
|
||||||
@ -1804,7 +1806,7 @@ function prepareTruncatedMemoryAndAst(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (value.type === 'TagIdentifier') {
|
if (value.type === 'TagIdentifier') {
|
||||||
programMemoryOverride.root[key] = JSON.parse(JSON.stringify(value))
|
programMemoryOverride.root[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1819,7 +1821,7 @@ function prepareTruncatedMemoryAndAst(
|
|||||||
if (!memoryItem) {
|
if (!memoryItem) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
programMemoryOverride.root[name] = JSON.parse(JSON.stringify(memoryItem))
|
programMemoryOverride.root[name] = memoryItem
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
truncatedAst,
|
truncatedAst,
|
||||||
@ -1967,9 +1969,9 @@ export async function getSketchOrientationDetails(
|
|||||||
* @param entityId - The ID of the entity for which orientation details are being fetched.
|
* @param entityId - The ID of the entity for which orientation details are being fetched.
|
||||||
* @returns A promise that resolves with the orientation details of the face.
|
* @returns A promise that resolves with the orientation details of the face.
|
||||||
*/
|
*/
|
||||||
async function getFaceDetails(
|
export async function getFaceDetails(
|
||||||
entityId: string
|
entityId: string
|
||||||
): Promise<Models['FaceIsPlanar_type']> {
|
): Promise<Models['GetSketchModePlane_type']> {
|
||||||
// TODO mode engine connection to allow batching returns and batch the following
|
// TODO mode engine connection to allow batching returns and batch the following
|
||||||
await engineCommandManager.sendSceneCommand({
|
await engineCommandManager.sendSceneCommand({
|
||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
@ -1982,8 +1984,7 @@ async function getFaceDetails(
|
|||||||
entity_id: entityId,
|
entity_id: entityId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
// TODO change typing to get_sketch_mode_plane once lib is updated
|
const faceInfo: Models['GetSketchModePlane_type'] = (
|
||||||
const faceInfo: Models['FaceIsPlanar_type'] = (
|
|
||||||
await engineCommandManager.sendSceneCommand({
|
await engineCommandManager.sendSceneCommand({
|
||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
cmd_id: uuidv4(),
|
cmd_id: uuidv4(),
|
||||||
|
@ -151,9 +151,7 @@ export function useCalc({
|
|||||||
ast,
|
ast,
|
||||||
engineCommandManager,
|
engineCommandManager,
|
||||||
useFakeExecutor: true,
|
useFakeExecutor: true,
|
||||||
programMemoryOverride: JSON.parse(
|
programMemoryOverride: kclManager.programMemory,
|
||||||
JSON.stringify(kclManager.programMemory)
|
|
||||||
),
|
|
||||||
}).then(({ programMemory }) => {
|
}).then(({ programMemory }) => {
|
||||||
const resultDeclaration = ast.body.find(
|
const resultDeclaration = ast.body.find(
|
||||||
(a) =>
|
(a) =>
|
||||||
|
@ -6,8 +6,18 @@ import { NetworkHealthIndicator } from 'components/NetworkHealthIndicator'
|
|||||||
import { HelpMenu } from './HelpMenu'
|
import { HelpMenu } from './HelpMenu'
|
||||||
import { Link, useLocation } from 'react-router-dom'
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
||||||
|
import { coreDump } from 'lang/wasm'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
|
import openWindow from 'lib/openWindow'
|
||||||
|
|
||||||
export function LowerRightControls(props: React.PropsWithChildren) {
|
export function LowerRightControls({
|
||||||
|
children,
|
||||||
|
coreDumpManager,
|
||||||
|
}: {
|
||||||
|
children?: React.ReactNode
|
||||||
|
coreDumpManager?: CoreDumpManager
|
||||||
|
}) {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const filePath = useAbsoluteFilePath()
|
const filePath = useAbsoluteFilePath()
|
||||||
const linkOverrideClassName =
|
const linkOverrideClassName =
|
||||||
@ -15,9 +25,42 @@ export function LowerRightControls(props: React.PropsWithChildren) {
|
|||||||
|
|
||||||
const isPlayWright = window?.localStorage.getItem('playwright') === 'true'
|
const isPlayWright = window?.localStorage.getItem('playwright') === 'true'
|
||||||
|
|
||||||
|
async function reportbug(event: { preventDefault: () => void }) {
|
||||||
|
event?.preventDefault()
|
||||||
|
|
||||||
|
if (!coreDumpManager) {
|
||||||
|
// open default reporting option
|
||||||
|
openWindow('https://github.com/KittyCAD/modeling-app/issues/new/choose')
|
||||||
|
} else {
|
||||||
|
toast
|
||||||
|
.promise(
|
||||||
|
coreDump(coreDumpManager, true),
|
||||||
|
{
|
||||||
|
loading: 'Preparing bug report...',
|
||||||
|
success: 'Bug report opened in new window',
|
||||||
|
error: 'Unable to export a core dump. Using default reporting.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
success: {
|
||||||
|
// Note: this extended duration is especially important for Playwright e2e testing
|
||||||
|
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
|
||||||
|
duration: 6000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err: Error) => {
|
||||||
|
if (err) {
|
||||||
|
openWindow(
|
||||||
|
'https://github.com/KittyCAD/modeling-app/issues/new/choose'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="fixed bottom-2 right-2 flex flex-col items-end gap-3 pointer-events-none">
|
<section className="fixed bottom-2 right-2 flex flex-col items-end gap-3 pointer-events-none">
|
||||||
{props.children}
|
{children}
|
||||||
<menu className="flex items-center justify-end gap-3 pointer-events-auto">
|
<menu className="flex items-center justify-end gap-3 pointer-events-auto">
|
||||||
<a
|
<a
|
||||||
href={`https://github.com/KittyCAD/modeling-app/releases/tag/v${APP_VERSION}`}
|
href={`https://github.com/KittyCAD/modeling-app/releases/tag/v${APP_VERSION}`}
|
||||||
@ -28,6 +71,7 @@ export function LowerRightControls(props: React.PropsWithChildren) {
|
|||||||
v{isPlayWright ? '11.22.33' : APP_VERSION}
|
v{isPlayWright ? '11.22.33' : APP_VERSION}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
|
onClick={reportbug}
|
||||||
href="https://github.com/KittyCAD/modeling-app/issues/new/choose"
|
href="https://github.com/KittyCAD/modeling-app/issues/new/choose"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
|
@ -30,7 +30,7 @@ import { wasmUrl } from 'lang/wasm'
|
|||||||
import { PROJECT_ENTRYPOINT } from 'lib/constants'
|
import { PROJECT_ENTRYPOINT } from 'lib/constants'
|
||||||
import { useNetworkContext } from 'hooks/useNetworkContext'
|
import { useNetworkContext } from 'hooks/useNetworkContext'
|
||||||
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||||
import { err, trap } from 'lib/trap'
|
import { err } from 'lib/trap'
|
||||||
|
|
||||||
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
|
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
|
||||||
return []
|
return []
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
editorManager,
|
editorManager,
|
||||||
sceneEntitiesManager,
|
sceneEntitiesManager,
|
||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
|
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
|
||||||
import {
|
import {
|
||||||
angleBetweenInfo,
|
angleBetweenInfo,
|
||||||
@ -78,6 +79,7 @@ import { getVarNameModal } from 'hooks/useToolbarGuards'
|
|||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { err, trap } from 'lib/trap'
|
import { err, trap } from 'lib/trap'
|
||||||
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
@ -124,7 +126,6 @@ export const ModelingMachineProvider = ({
|
|||||||
token
|
token
|
||||||
)
|
)
|
||||||
useHotkeyWrapper(['meta + shift + .'], () => {
|
useHotkeyWrapper(['meta + shift + .'], () => {
|
||||||
console.warn('CoreDump: Initializing core dump')
|
|
||||||
toast.promise(
|
toast.promise(
|
||||||
coreDump(coreDumpManager, true),
|
coreDump(coreDumpManager, true),
|
||||||
{
|
{
|
||||||
@ -141,6 +142,7 @@ export const ModelingMachineProvider = ({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
const { commandBarState } = useCommandsContext()
|
||||||
|
|
||||||
// Settings machine setup
|
// Settings machine setup
|
||||||
// const retrievedSettings = useRef(
|
// const retrievedSettings = useRef(
|
||||||
@ -465,6 +467,11 @@ export const ModelingMachineProvider = ({
|
|||||||
|
|
||||||
return canExtrudeSelection(selectionRanges)
|
return canExtrudeSelection(selectionRanges)
|
||||||
},
|
},
|
||||||
|
'has valid selection for deletion': ({ selectionRanges }) => {
|
||||||
|
if (!commandBarState.matches('Closed')) return false
|
||||||
|
if (selectionRanges.codeBasedSelections.length <= 0) return false
|
||||||
|
return true
|
||||||
|
},
|
||||||
'Sketch is empty': ({ sketchDetails }) => {
|
'Sketch is empty': ({ sketchDetails }) => {
|
||||||
const node = getNodeFromPath<VariableDeclaration>(
|
const node = getNodeFromPath<VariableDeclaration>(
|
||||||
kclManager.ast,
|
kclManager.ast,
|
||||||
@ -506,7 +513,7 @@ export const ModelingMachineProvider = ({
|
|||||||
services: {
|
services: {
|
||||||
'AST-undo-startSketchOn': async ({ sketchDetails }) => {
|
'AST-undo-startSketchOn': async ({ sketchDetails }) => {
|
||||||
if (!sketchDetails) return
|
if (!sketchDetails) return
|
||||||
const newAst: Program = JSON.parse(JSON.stringify(kclManager.ast))
|
const newAst: Program = kclManager.ast
|
||||||
const varDecIndex = sketchDetails.sketchPathToNode[1][0]
|
const varDecIndex = sketchDetails.sketchPathToNode[1][0]
|
||||||
// remove body item at varDecIndex
|
// remove body item at varDecIndex
|
||||||
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
|
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
|
||||||
@ -928,6 +935,11 @@ export const ModelingMachineProvider = ({
|
|||||||
}
|
}
|
||||||
}, [modelingSend])
|
}, [modelingSend])
|
||||||
|
|
||||||
|
// Allow using the delete key to delete solids
|
||||||
|
useHotkeys(['backspace', 'delete', 'del'], () => {
|
||||||
|
modelingSend({ type: 'Delete selection' })
|
||||||
|
})
|
||||||
|
|
||||||
useStateMachineCommands({
|
useStateMachineCommands({
|
||||||
machineId: 'modeling',
|
machineId: 'modeling',
|
||||||
state: modelingState,
|
state: modelingState,
|
||||||
|
@ -1,7 +1,25 @@
|
|||||||
|
import { coreDump } from 'lang/wasm'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
|
import { engineCommandManager } from 'lib/singletons'
|
||||||
|
import React from 'react'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
|
||||||
|
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
||||||
|
const { auth } = useSettingsAuthContext()
|
||||||
|
const token = auth?.context?.token
|
||||||
|
const { htmlRef } = useStore((s) => ({
|
||||||
|
htmlRef: s.htmlRef,
|
||||||
|
}))
|
||||||
|
const coreDumpManager = new CoreDumpManager(
|
||||||
|
engineCommandManager,
|
||||||
|
htmlRef,
|
||||||
|
token
|
||||||
|
)
|
||||||
|
|
||||||
export function RefreshButton() {
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
if (window && 'plausible' in window) {
|
if (window && 'plausible' in window) {
|
||||||
const p = window.plausible as (
|
const p = window.plausible as (
|
||||||
@ -17,8 +35,26 @@ export function RefreshButton() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window may not be available in some environments
|
toast
|
||||||
window?.location.reload()
|
.promise(
|
||||||
|
coreDump(coreDumpManager, true),
|
||||||
|
{
|
||||||
|
loading: 'Starting core dump...',
|
||||||
|
success: 'Core dump completed successfully',
|
||||||
|
error: 'Error while exporting core dump',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
success: {
|
||||||
|
// Note: this extended duration is especially important for Playwright e2e testing
|
||||||
|
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
|
||||||
|
duration: 6000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
// Window may not be available in some environments
|
||||||
|
window?.location.reload()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -83,6 +83,7 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
if (!videoRef.current) return
|
if (!videoRef.current) return
|
||||||
if (state.matches('Sketch')) return
|
if (state.matches('Sketch')) return
|
||||||
if (state.matches('Sketch no face')) return
|
if (state.matches('Sketch no face')) return
|
||||||
|
|
||||||
const { x, y } = getNormalisedCoordinates({
|
const { x, y } = getNormalisedCoordinates({
|
||||||
clientX: e.clientX,
|
clientX: e.clientX,
|
||||||
clientY: e.clientY,
|
clientY: e.clientY,
|
||||||
|
@ -145,7 +145,7 @@ export async function applyConstraintIntersect({
|
|||||||
const { transforms, forcedSelectionRanges } = info
|
const { transforms, forcedSelectionRanges } = info
|
||||||
|
|
||||||
const transform1 = transformSecondarySketchLinesTagFirst({
|
const transform1 = transformSecondarySketchLinesTagFirst({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges: forcedSelectionRanges,
|
selectionRanges: forcedSelectionRanges,
|
||||||
transformInfos: transforms,
|
transformInfos: transforms,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
|
@ -106,7 +106,7 @@ export async function applyConstraintAbsDistance({
|
|||||||
const transformInfos = info.transforms
|
const transformInfos = info.transforms
|
||||||
|
|
||||||
const transform1 = transformAstSketchLines({
|
const transform1 = transformAstSketchLines({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges: selectionRanges,
|
selectionRanges: selectionRanges,
|
||||||
transformInfos,
|
transformInfos,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
@ -128,7 +128,7 @@ export async function applyConstraintAbsDistance({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const transform2 = transformAstSketchLines({
|
const transform2 = transformAstSketchLines({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges: selectionRanges,
|
selectionRanges: selectionRanges,
|
||||||
transformInfos,
|
transformInfos,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
@ -176,7 +176,7 @@ export function applyConstraintAxisAlign({
|
|||||||
let finalValue = createIdentifier('ZERO')
|
let finalValue = createIdentifier('ZERO')
|
||||||
|
|
||||||
return transformAstSketchLines({
|
return transformAstSketchLines({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges: selectionRanges,
|
selectionRanges: selectionRanges,
|
||||||
transformInfos,
|
transformInfos,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
|
@ -100,7 +100,7 @@ export async function applyConstraintAngleBetween({
|
|||||||
const transformInfos = info.transforms
|
const transformInfos = info.transforms
|
||||||
|
|
||||||
const transformed1 = transformSecondarySketchLinesTagFirst({
|
const transformed1 = transformSecondarySketchLinesTagFirst({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
transformInfos,
|
transformInfos,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
|
@ -108,7 +108,7 @@ export async function applyConstraintHorzVertDistance({
|
|||||||
if (err(info)) return Promise.reject(info)
|
if (err(info)) return Promise.reject(info)
|
||||||
const transformInfos = info.transforms
|
const transformInfos = info.transforms
|
||||||
const transformed = transformSecondarySketchLinesTagFirst({
|
const transformed = transformSecondarySketchLinesTagFirst({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
transformInfos,
|
transformInfos,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
|
@ -84,7 +84,7 @@ export async function applyConstraintAngleLength({
|
|||||||
|
|
||||||
const { transforms } = angleLength
|
const { transforms } = angleLength
|
||||||
const sketched = transformAstSketchLines({
|
const sketched = transformAstSketchLines({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
transformInfos: transforms,
|
transformInfos: transforms,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
@ -139,7 +139,7 @@ export async function applyConstraintAngleLength({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const retval = transformAstSketchLines({
|
const retval = transformAstSketchLines({
|
||||||
ast: JSON.parse(JSON.stringify(kclManager.ast)),
|
ast: kclManager.ast,
|
||||||
selectionRanges,
|
selectionRanges,
|
||||||
transformInfos: transforms,
|
transformInfos: transforms,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
|
@ -42,9 +42,8 @@ function registerServerCapability(
|
|||||||
serverCapabilities: ServerCapabilities,
|
serverCapabilities: ServerCapabilities,
|
||||||
registration: Registration
|
registration: Registration
|
||||||
): ServerCapabilities | Error {
|
): ServerCapabilities | Error {
|
||||||
const serverCapabilitiesCopy = JSON.parse(
|
const serverCapabilitiesCopy =
|
||||||
JSON.stringify(serverCapabilities)
|
serverCapabilities as IFlexibleServerCapabilities
|
||||||
) as IFlexibleServerCapabilities
|
|
||||||
const { method, registerOptions } = registration
|
const { method, registerOptions } = registration
|
||||||
const providerName = ServerCapabilitiesProviders[method]
|
const providerName = ServerCapabilitiesProviders[method]
|
||||||
|
|
||||||
@ -52,10 +51,7 @@ function registerServerCapability(
|
|||||||
if (!registerOptions) {
|
if (!registerOptions) {
|
||||||
serverCapabilitiesCopy[providerName] = true
|
serverCapabilitiesCopy[providerName] = true
|
||||||
} else {
|
} else {
|
||||||
serverCapabilitiesCopy[providerName] = Object.assign(
|
serverCapabilitiesCopy[providerName] = Object.assign({}, registerOptions)
|
||||||
{},
|
|
||||||
JSON.parse(JSON.stringify(registerOptions))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new Error('Could not register server capability.')
|
return new Error('Could not register server capability.')
|
||||||
@ -68,9 +64,8 @@ function unregisterServerCapability(
|
|||||||
serverCapabilities: ServerCapabilities,
|
serverCapabilities: ServerCapabilities,
|
||||||
unregistration: Unregistration
|
unregistration: Unregistration
|
||||||
): ServerCapabilities {
|
): ServerCapabilities {
|
||||||
const serverCapabilitiesCopy = JSON.parse(
|
const serverCapabilitiesCopy =
|
||||||
JSON.stringify(serverCapabilities)
|
serverCapabilities as IFlexibleServerCapabilities
|
||||||
) as IFlexibleServerCapabilities
|
|
||||||
const { method } = unregistration
|
const { method } = unregistration
|
||||||
const providerName = ServerCapabilitiesProviders[method]
|
const providerName = ServerCapabilitiesProviders[method]
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
sketchOnExtrudedFace,
|
sketchOnExtrudedFace,
|
||||||
deleteSegmentFromPipeExpression,
|
deleteSegmentFromPipeExpression,
|
||||||
removeSingleConstraintInfo,
|
removeSingleConstraintInfo,
|
||||||
|
deleteFromSelection,
|
||||||
} from './modifyAst'
|
} from './modifyAst'
|
||||||
import { enginelessExecutor } from '../lib/testHelpers'
|
import { enginelessExecutor } from '../lib/testHelpers'
|
||||||
import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst'
|
import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst'
|
||||||
@ -696,3 +697,196 @@ describe('Testing removeSingleConstraintInfo', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Testing deleteFromSelection', () => {
|
||||||
|
const cases = [
|
||||||
|
[
|
||||||
|
'basicCase',
|
||||||
|
{
|
||||||
|
codeBefore: `const myVar = 5
|
||||||
|
const sketch003 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([3.82, 13.6], %)
|
||||||
|
|> line([-2.94, 2.7], %)
|
||||||
|
|> line([7.7, 0.16], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)`,
|
||||||
|
codeAfter: `const myVar = 5\n`,
|
||||||
|
lineOfInterest: 'line([-2.94, 2.7], %)',
|
||||||
|
type: 'default',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'delete extrude',
|
||||||
|
{
|
||||||
|
codeBefore: `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], %, $seg01)
|
||||||
|
|> line([-3.86, -2.73], %)
|
||||||
|
|> line([-17.67, 0.85], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(10, sketch001)`,
|
||||||
|
codeAfter: `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], %, $seg01)
|
||||||
|
|> line([-3.86, -2.73], %)
|
||||||
|
|> line([-17.67, 0.85], %)
|
||||||
|
|> close(%)\n`,
|
||||||
|
lineOfInterest: 'line([2.66, 1.17], %)',
|
||||||
|
type: 'extrude-wall',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'delete extrude with sketch on it',
|
||||||
|
{
|
||||||
|
codeBefore: `const myVar = 5
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([4.46, 5.12], %, $tag)
|
||||||
|
|> line([0.08, myVar], %)
|
||||||
|
|> line([13.03, 2.02], %, $seg01)
|
||||||
|
|> line([3.9, -7.6], %)
|
||||||
|
|> line([-11.18, -2.15], %)
|
||||||
|
|> line([5.41, -9.61], %)
|
||||||
|
|> line([-8.54, -2.51], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(5, sketch001)
|
||||||
|
const sketch002 = startSketchOn(extrude001, seg01)
|
||||||
|
|> startProfileAt([-12.55, 2.89], %)
|
||||||
|
|> line([3.02, 1.9], %)
|
||||||
|
|> line([1.82, -1.49], %, $seg02)
|
||||||
|
|> angledLine([-86, segLen(seg02, %)], %)
|
||||||
|
|> line([-3.97, -0.53], %)
|
||||||
|
|> line([0.3, 0.84], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)`,
|
||||||
|
codeAfter: `const myVar = 5
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([4.46, 5.12], %, $tag)
|
||||||
|
|> line([0.08, myVar], %)
|
||||||
|
|> line([13.03, 2.02], %, $seg01)
|
||||||
|
|> line([3.9, -7.6], %)
|
||||||
|
|> line([-11.18, -2.15], %)
|
||||||
|
|> line([5.41, -9.61], %)
|
||||||
|
|> line([-8.54, -2.51], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const sketch002 = startSketchOn({
|
||||||
|
plane: {
|
||||||
|
origin: { x: 1, y: 2, z: 3 },
|
||||||
|
x_axis: { x: 4, y: 5, z: 6 },
|
||||||
|
y_axis: { x: 7, y: 8, z: 9 },
|
||||||
|
z_axis: { x: 10, y: 11, z: 12 }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> startProfileAt([-12.55, 2.89], %)
|
||||||
|
|> line([3.02, 1.9], %)
|
||||||
|
|> line([1.82, -1.49], %, $seg02)
|
||||||
|
|> angledLine([-86, segLen(seg02, %)], %)
|
||||||
|
|> line([-3.97, -0.53], %)
|
||||||
|
|> line([0.3, 0.84], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
`,
|
||||||
|
lineOfInterest: 'line([-11.18, -2.15], %)',
|
||||||
|
type: 'extrude-wall',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'delete extrude with sketch on it',
|
||||||
|
{
|
||||||
|
codeBefore: `const myVar = 5
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([4.46, 5.12], %, $tag)
|
||||||
|
|> line([0.08, myVar], %)
|
||||||
|
|> line([13.03, 2.02], %, $seg01)
|
||||||
|
|> line([3.9, -7.6], %)
|
||||||
|
|> line([-11.18, -2.15], %)
|
||||||
|
|> line([5.41, -9.61], %)
|
||||||
|
|> line([-8.54, -2.51], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const extrude001 = extrude(5, sketch001)
|
||||||
|
const sketch002 = startSketchOn(extrude001, seg01)
|
||||||
|
|> startProfileAt([-12.55, 2.89], %)
|
||||||
|
|> line([3.02, 1.9], %)
|
||||||
|
|> line([1.82, -1.49], %, $seg02)
|
||||||
|
|> angledLine([-86, segLen(seg02, %)], %)
|
||||||
|
|> line([-3.97, -0.53], %)
|
||||||
|
|> line([0.3, 0.84], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)`,
|
||||||
|
codeAfter: `const myVar = 5
|
||||||
|
const sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([4.46, 5.12], %, $tag)
|
||||||
|
|> line([0.08, myVar], %)
|
||||||
|
|> line([13.03, 2.02], %, $seg01)
|
||||||
|
|> line([3.9, -7.6], %)
|
||||||
|
|> line([-11.18, -2.15], %)
|
||||||
|
|> line([5.41, -9.61], %)
|
||||||
|
|> line([-8.54, -2.51], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
const sketch002 = startSketchOn({
|
||||||
|
plane: {
|
||||||
|
origin: { x: 1, y: 2, z: 3 },
|
||||||
|
x_axis: { x: 4, y: 5, z: 6 },
|
||||||
|
y_axis: { x: 7, y: 8, z: 9 },
|
||||||
|
z_axis: { x: 10, y: 11, z: 12 }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|> startProfileAt([-12.55, 2.89], %)
|
||||||
|
|> line([3.02, 1.9], %)
|
||||||
|
|> line([1.82, -1.49], %, $seg02)
|
||||||
|
|> angledLine([-86, segLen(seg02, %)], %)
|
||||||
|
|> line([-3.97, -0.53], %)
|
||||||
|
|> line([0.3, 0.84], %)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
`,
|
||||||
|
lineOfInterest: 'startProfileAt([4.46, 5.12], %, $tag)',
|
||||||
|
type: 'end-cap',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
] as const
|
||||||
|
test.each(cases)(
|
||||||
|
'%s',
|
||||||
|
async (name, { codeBefore, codeAfter, lineOfInterest, type }) => {
|
||||||
|
// const lineOfInterest = 'line([-2.94, 2.7], %)'
|
||||||
|
const ast = parse(codeBefore)
|
||||||
|
if (err(ast)) throw ast
|
||||||
|
const programMemory = await enginelessExecutor(ast)
|
||||||
|
|
||||||
|
// deleteFromSelection
|
||||||
|
const range: [number, number] = [
|
||||||
|
codeBefore.indexOf(lineOfInterest),
|
||||||
|
codeBefore.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||||
|
]
|
||||||
|
const newAst = await deleteFromSelection(
|
||||||
|
ast,
|
||||||
|
{
|
||||||
|
range,
|
||||||
|
type,
|
||||||
|
},
|
||||||
|
programMemory,
|
||||||
|
async () => {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||||
|
return {
|
||||||
|
origin: { x: 1, y: 2, z: 3 },
|
||||||
|
x_axis: { x: 4, y: 5, z: 6 },
|
||||||
|
y_axis: { x: 7, y: 8, z: 9 },
|
||||||
|
z_axis: { x: 10, y: 11, z: 12 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (err(newAst)) throw newAst
|
||||||
|
const newCode = recast(newAst)
|
||||||
|
expect(newCode).toBe(codeAfter)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@ -17,6 +17,7 @@ import {
|
|||||||
PathToNode,
|
PathToNode,
|
||||||
ProgramMemory,
|
ProgramMemory,
|
||||||
SourceRange,
|
SourceRange,
|
||||||
|
SketchGroup,
|
||||||
} from './wasm'
|
} from './wasm'
|
||||||
import {
|
import {
|
||||||
isNodeSafeToReplacePath,
|
isNodeSafeToReplacePath,
|
||||||
@ -25,6 +26,7 @@ import {
|
|||||||
getNodeFromPath,
|
getNodeFromPath,
|
||||||
getNodePathFromSourceRange,
|
getNodePathFromSourceRange,
|
||||||
isNodeSafeToReplace,
|
isNodeSafeToReplace,
|
||||||
|
traverse,
|
||||||
} from './queryAst'
|
} from './queryAst'
|
||||||
import { addTagForSketchOnFace, getConstraintInfo } from './std/sketch'
|
import { addTagForSketchOnFace, getConstraintInfo } from './std/sketch'
|
||||||
import {
|
import {
|
||||||
@ -38,6 +40,7 @@ import { isOverlap, roundOff } from 'lib/utils'
|
|||||||
import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants'
|
import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants'
|
||||||
import { ConstrainInfo } from './std/stdTypes'
|
import { ConstrainInfo } from './std/stdTypes'
|
||||||
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
|
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
|
||||||
|
import { Models } from '@kittycad/lib'
|
||||||
|
|
||||||
export function startSketchOnDefault(
|
export function startSketchOnDefault(
|
||||||
node: Program,
|
node: Program,
|
||||||
@ -707,7 +710,7 @@ export function moveValueIntoNewVariablePath(
|
|||||||
programMemory,
|
programMemory,
|
||||||
pathToNode
|
pathToNode
|
||||||
)
|
)
|
||||||
let _node = JSON.parse(JSON.stringify(ast))
|
let _node = ast
|
||||||
const boop = replacer(_node, variableName)
|
const boop = replacer(_node, variableName)
|
||||||
if (trap(boop)) return { modifiedAst: ast }
|
if (trap(boop)) return { modifiedAst: ast }
|
||||||
|
|
||||||
@ -739,7 +742,7 @@ export function moveValueIntoNewVariable(
|
|||||||
programMemory,
|
programMemory,
|
||||||
sourceRange
|
sourceRange
|
||||||
)
|
)
|
||||||
let _node = JSON.parse(JSON.stringify(ast))
|
let _node = ast
|
||||||
const replaced = replacer(_node, variableName)
|
const replaced = replacer(_node, variableName)
|
||||||
if (trap(replaced)) return { modifiedAst: ast }
|
if (trap(replaced)) return { modifiedAst: ast }
|
||||||
|
|
||||||
@ -764,7 +767,7 @@ export function deleteSegmentFromPipeExpression(
|
|||||||
code: string,
|
code: string,
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
): Program | Error {
|
): Program | Error {
|
||||||
let _modifiedAst: Program = JSON.parse(JSON.stringify(modifiedAst))
|
let _modifiedAst: Program = modifiedAst
|
||||||
|
|
||||||
dependentRanges.forEach((range) => {
|
dependentRanges.forEach((range) => {
|
||||||
const path = getNodePathFromSourceRange(_modifiedAst, range)
|
const path = getNodePathFromSourceRange(_modifiedAst, range)
|
||||||
@ -873,3 +876,175 @@ export function removeSingleConstraintInfo(
|
|||||||
if (err(retval)) return false
|
if (err(retval)) return false
|
||||||
return retval
|
return retval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteFromSelection(
|
||||||
|
ast: Program,
|
||||||
|
selection: Selection,
|
||||||
|
programMemory: ProgramMemory,
|
||||||
|
getFaceDetails: (id: string) => Promise<Models['FaceIsPlanar_type']> = () =>
|
||||||
|
({} as any)
|
||||||
|
): Promise<Program | Error> {
|
||||||
|
const astClone = ast
|
||||||
|
const range = selection.range
|
||||||
|
const path = getNodePathFromSourceRange(ast, range)
|
||||||
|
const varDec = getNodeFromPath<VariableDeclarator>(
|
||||||
|
ast,
|
||||||
|
path,
|
||||||
|
'VariableDeclarator'
|
||||||
|
)
|
||||||
|
if (err(varDec)) return varDec
|
||||||
|
if (
|
||||||
|
(selection.type === 'extrude-wall' ||
|
||||||
|
selection.type === 'end-cap' ||
|
||||||
|
selection.type === 'start-cap') &&
|
||||||
|
varDec.node.init.type === 'PipeExpression'
|
||||||
|
) {
|
||||||
|
const varDecName = varDec.node.id.name
|
||||||
|
let pathToNode: PathToNode | null = null
|
||||||
|
let extrudeNameToDelete = ''
|
||||||
|
traverse(astClone, {
|
||||||
|
enter: (node, path) => {
|
||||||
|
if (node.type === 'VariableDeclaration') {
|
||||||
|
const dec = node.declarations[0]
|
||||||
|
if (
|
||||||
|
dec.init.type === 'CallExpression' &&
|
||||||
|
(dec.init.callee.name === 'extrude' ||
|
||||||
|
dec.init.callee.name === 'revolve') &&
|
||||||
|
dec.init.arguments?.[1].type === 'Identifier' &&
|
||||||
|
dec.init.arguments?.[1].name === varDecName
|
||||||
|
) {
|
||||||
|
pathToNode = path
|
||||||
|
extrudeNameToDelete = dec.id.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!pathToNode) return new Error('Could not find extrude variable')
|
||||||
|
|
||||||
|
const expressionIndex = pathToNode[1][0] as number
|
||||||
|
astClone.body.splice(expressionIndex, 1)
|
||||||
|
if (extrudeNameToDelete) {
|
||||||
|
await new Promise(async (resolve) => {
|
||||||
|
let currentVariableName = ''
|
||||||
|
const pathsDependingOnExtrude: Array<{
|
||||||
|
path: PathToNode
|
||||||
|
sketchName: string
|
||||||
|
}> = []
|
||||||
|
traverse(astClone, {
|
||||||
|
leave: (node) => {
|
||||||
|
if (node.type === 'VariableDeclaration') {
|
||||||
|
currentVariableName = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enter: async (node, path) => {
|
||||||
|
if (node.type === 'VariableDeclaration') {
|
||||||
|
currentVariableName = node.declarations[0].id.name
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
// match startSketchOn(${extrudeNameToDelete})
|
||||||
|
node.type === 'CallExpression' &&
|
||||||
|
node.callee.name === 'startSketchOn' &&
|
||||||
|
node.arguments[0].type === 'Identifier' &&
|
||||||
|
node.arguments[0].name === extrudeNameToDelete
|
||||||
|
) {
|
||||||
|
pathsDependingOnExtrude.push({
|
||||||
|
path,
|
||||||
|
sketchName: currentVariableName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const roundLiteral = (x: number) => createLiteral(roundOff(x))
|
||||||
|
const modificationDetails: {
|
||||||
|
parent: PipeExpression['body']
|
||||||
|
faceDetails: Models['FaceIsPlanar_type']
|
||||||
|
lastKey: number
|
||||||
|
}[] = []
|
||||||
|
for (const { path, sketchName } of pathsDependingOnExtrude) {
|
||||||
|
const parent = getNodeFromPath<PipeExpression['body']>(
|
||||||
|
astClone,
|
||||||
|
path.slice(0, -1)
|
||||||
|
)
|
||||||
|
if (err(parent)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const sketchToPreserve = programMemory.root[sketchName] as SketchGroup
|
||||||
|
console.log('sketchName', sketchName)
|
||||||
|
// Can't kick off multiple requests at once as getFaceDetails
|
||||||
|
// is three engine calls in one and they conflict
|
||||||
|
const faceDetails = await getFaceDetails(sketchToPreserve.on.id)
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
faceDetails.origin &&
|
||||||
|
faceDetails.x_axis &&
|
||||||
|
faceDetails.y_axis &&
|
||||||
|
faceDetails.z_axis
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const lastKey = Number(path.slice(-1)[0][0])
|
||||||
|
modificationDetails.push({
|
||||||
|
parent: parent.node,
|
||||||
|
faceDetails,
|
||||||
|
lastKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for (const { parent, faceDetails, lastKey } of modificationDetails) {
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
faceDetails.origin &&
|
||||||
|
faceDetails.x_axis &&
|
||||||
|
faceDetails.y_axis &&
|
||||||
|
faceDetails.z_axis
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parent[lastKey] = createCallExpressionStdLib('startSketchOn', [
|
||||||
|
createObjectExpression({
|
||||||
|
plane: createObjectExpression({
|
||||||
|
origin: createObjectExpression({
|
||||||
|
x: roundLiteral(faceDetails.origin.x),
|
||||||
|
y: roundLiteral(faceDetails.origin.y),
|
||||||
|
z: roundLiteral(faceDetails.origin.z),
|
||||||
|
}),
|
||||||
|
x_axis: createObjectExpression({
|
||||||
|
x: roundLiteral(faceDetails.x_axis.x),
|
||||||
|
y: roundLiteral(faceDetails.x_axis.y),
|
||||||
|
z: roundLiteral(faceDetails.x_axis.z),
|
||||||
|
}),
|
||||||
|
y_axis: createObjectExpression({
|
||||||
|
x: roundLiteral(faceDetails.y_axis.x),
|
||||||
|
y: roundLiteral(faceDetails.y_axis.y),
|
||||||
|
z: roundLiteral(faceDetails.y_axis.z),
|
||||||
|
}),
|
||||||
|
z_axis: createObjectExpression({
|
||||||
|
x: roundLiteral(faceDetails.z_axis.x),
|
||||||
|
y: roundLiteral(faceDetails.z_axis.y),
|
||||||
|
z: roundLiteral(faceDetails.z_axis.z),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// await prom
|
||||||
|
return astClone
|
||||||
|
} else if (varDec.node.init.type === 'PipeExpression') {
|
||||||
|
const pipeBody = varDec.node.init.body
|
||||||
|
if (
|
||||||
|
pipeBody[0].type === 'CallExpression' &&
|
||||||
|
pipeBody[0].callee.name === 'startSketchOn'
|
||||||
|
) {
|
||||||
|
// remove varDec
|
||||||
|
const varDecIndex = varDec.shallowPath[1][0] as number
|
||||||
|
astClone.body.splice(varDecIndex, 1)
|
||||||
|
return astClone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Error('Selection not recognised, could not delete')
|
||||||
|
}
|
||||||
|
@ -87,10 +87,7 @@ const yo2 = hmm([identifierGuy + 5])`
|
|||||||
expect(result.isSafe).toBe(true)
|
expect(result.isSafe).toBe(true)
|
||||||
expect(result.value?.type).toBe('BinaryExpression')
|
expect(result.value?.type).toBe('BinaryExpression')
|
||||||
expect(code.slice(result.value.start, result.value.end)).toBe('100 + 100')
|
expect(code.slice(result.value.start, result.value.end)).toBe('100 + 100')
|
||||||
const replaced = result.replacer(
|
const replaced = result.replacer(ast, 'replaceName')
|
||||||
JSON.parse(JSON.stringify(ast)),
|
|
||||||
'replaceName'
|
|
||||||
)
|
|
||||||
if (err(replaced)) throw replaced
|
if (err(replaced)) throw replaced
|
||||||
const outCode = recast(replaced.modifiedAst)
|
const outCode = recast(replaced.modifiedAst)
|
||||||
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
|
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
|
||||||
@ -114,10 +111,7 @@ const yo2 = hmm([identifierGuy + 5])`
|
|||||||
expect(result.isSafe).toBe(true)
|
expect(result.isSafe).toBe(true)
|
||||||
expect(result.value?.type).toBe('CallExpression')
|
expect(result.value?.type).toBe('CallExpression')
|
||||||
expect(code.slice(result.value.start, result.value.end)).toBe("def('yo')")
|
expect(code.slice(result.value.start, result.value.end)).toBe("def('yo')")
|
||||||
const replaced = result.replacer(
|
const replaced = result.replacer(ast, 'replaceName')
|
||||||
JSON.parse(JSON.stringify(ast)),
|
|
||||||
'replaceName'
|
|
||||||
)
|
|
||||||
if (err(replaced)) throw replaced
|
if (err(replaced)) throw replaced
|
||||||
const outCode = recast(replaced.modifiedAst)
|
const outCode = recast(replaced.modifiedAst)
|
||||||
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
|
expect(outCode).toContain(`angledLine([replaceName, 3.09], %)`)
|
||||||
@ -154,10 +148,7 @@ const yo2 = hmm([identifierGuy + 5])`
|
|||||||
expect(result.isSafe).toBe(true)
|
expect(result.isSafe).toBe(true)
|
||||||
expect(result.value?.type).toBe('BinaryExpression')
|
expect(result.value?.type).toBe('BinaryExpression')
|
||||||
expect(code.slice(result.value.start, result.value.end)).toBe('5 + 6')
|
expect(code.slice(result.value.start, result.value.end)).toBe('5 + 6')
|
||||||
const replaced = result.replacer(
|
const replaced = result.replacer(ast, 'replaceName')
|
||||||
JSON.parse(JSON.stringify(ast)),
|
|
||||||
'replaceName'
|
|
||||||
)
|
|
||||||
if (err(replaced)) throw replaced
|
if (err(replaced)) throw replaced
|
||||||
const outCode = recast(replaced.modifiedAst)
|
const outCode = recast(replaced.modifiedAst)
|
||||||
expect(outCode).toContain(`const yo = replaceName`)
|
expect(outCode).toContain(`const yo = replaceName`)
|
||||||
@ -173,10 +164,7 @@ const yo2 = hmm([identifierGuy + 5])`
|
|||||||
expect(code.slice(result.value.start, result.value.end)).toBe(
|
expect(code.slice(result.value.start, result.value.end)).toBe(
|
||||||
"jkl('yo') + 2"
|
"jkl('yo') + 2"
|
||||||
)
|
)
|
||||||
const replaced = result.replacer(
|
const replaced = result.replacer(ast, 'replaceName')
|
||||||
JSON.parse(JSON.stringify(ast)),
|
|
||||||
'replaceName'
|
|
||||||
)
|
|
||||||
if (err(replaced)) throw replaced
|
if (err(replaced)) throw replaced
|
||||||
const { modifiedAst } = replaced
|
const { modifiedAst } = replaced
|
||||||
const outCode = recast(modifiedAst)
|
const outCode = recast(modifiedAst)
|
||||||
@ -195,10 +183,7 @@ const yo2 = hmm([identifierGuy + 5])`
|
|||||||
expect(code.slice(result.value.start, result.value.end)).toBe(
|
expect(code.slice(result.value.start, result.value.end)).toBe(
|
||||||
'identifierGuy + 5'
|
'identifierGuy + 5'
|
||||||
)
|
)
|
||||||
const replaced = result.replacer(
|
const replaced = result.replacer(ast, 'replaceName')
|
||||||
JSON.parse(JSON.stringify(ast)),
|
|
||||||
'replaceName'
|
|
||||||
)
|
|
||||||
if (err(replaced)) throw replaced
|
if (err(replaced)) throw replaced
|
||||||
const { modifiedAst } = replaced
|
const { modifiedAst } = replaced
|
||||||
const outCode = recast(modifiedAst)
|
const outCode = recast(modifiedAst)
|
||||||
|
@ -520,8 +520,8 @@ export function isNodeSafeToReplacePath(
|
|||||||
const replaceNodeWithIdentifier: ReplacerFn = (_ast, varName) => {
|
const replaceNodeWithIdentifier: ReplacerFn = (_ast, varName) => {
|
||||||
const identifier = createIdentifier(varName)
|
const identifier = createIdentifier(varName)
|
||||||
const last = finPath[finPath.length - 1]
|
const last = finPath[finPath.length - 1]
|
||||||
const pathToReplaced = JSON.parse(JSON.stringify(finPath))
|
const pathToReplaced = finPath
|
||||||
pathToReplaced[1][0] = pathToReplaced[1][0] + 1
|
pathToReplaced[1][0] = (pathToReplaced[1][0] as number) + 1
|
||||||
const startPath = finPath.slice(0, -1)
|
const startPath = finPath.slice(0, -1)
|
||||||
const _nodeToReplace = getNodeFromPath(_ast, startPath)
|
const _nodeToReplace = getNodeFromPath(_ast, startPath)
|
||||||
if (err(_nodeToReplace)) return _nodeToReplace
|
if (err(_nodeToReplace)) return _nodeToReplace
|
||||||
|
@ -24,11 +24,7 @@ import {
|
|||||||
isNotLiteralArrayOrStatic,
|
isNotLiteralArrayOrStatic,
|
||||||
} from 'lang/std/sketchcombos'
|
} from 'lang/std/sketchcombos'
|
||||||
import { toolTips, ToolTip } from '../../useStore'
|
import { toolTips, ToolTip } from '../../useStore'
|
||||||
import {
|
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
||||||
createIdentifier,
|
|
||||||
createPipeExpression,
|
|
||||||
splitPathAtPipeExpression,
|
|
||||||
} from '../modifyAst'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SketchLineHelper,
|
SketchLineHelper,
|
||||||
|
@ -1496,7 +1496,7 @@ export function transformSecondarySketchLinesTagFirst({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
| Error {
|
| Error {
|
||||||
// let node = JSON.parse(JSON.stringify(ast))
|
// let node = ast
|
||||||
const primarySelection = selectionRanges.codeBasedSelections[0].range
|
const primarySelection = selectionRanges.codeBasedSelections[0].range
|
||||||
|
|
||||||
const _tag = giveSketchFnCallTag(ast, primarySelection, forceSegName)
|
const _tag = giveSketchFnCallTag(ast, primarySelection, forceSegName)
|
||||||
@ -1565,7 +1565,7 @@ export function transformAstSketchLines({
|
|||||||
}
|
}
|
||||||
| Error {
|
| Error {
|
||||||
// deep clone since we are mutating in a loop, of which any could fail
|
// deep clone since we are mutating in a loop, of which any could fail
|
||||||
let node = JSON.parse(JSON.stringify(ast))
|
let node = ast
|
||||||
let _valueUsedInTransform // TODO should this be an array?
|
let _valueUsedInTransform // TODO should this be an array?
|
||||||
const pathToNodeMap: PathToNodeMap = {}
|
const pathToNodeMap: PathToNodeMap = {}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ export function updatePathToNodeFromMap(
|
|||||||
oldPath: PathToNode,
|
oldPath: PathToNode,
|
||||||
pathToNodeMap: { [key: number]: PathToNode }
|
pathToNodeMap: { [key: number]: PathToNode }
|
||||||
): PathToNode {
|
): PathToNode {
|
||||||
const updatedPathToNode = JSON.parse(JSON.stringify(oldPath))
|
const updatedPathToNode = oldPath
|
||||||
let max = 0
|
let max = 0
|
||||||
Object.values(pathToNodeMap).forEach((path) => {
|
Object.values(pathToNodeMap).forEach((path) => {
|
||||||
const index = Number(path[1][0])
|
const index = Number(path[1][0])
|
||||||
|
@ -334,6 +334,7 @@ export async function coreDump(
|
|||||||
openGithubIssue: boolean = false
|
openGithubIssue: boolean = false
|
||||||
): Promise<CoreDumpInfo> {
|
): Promise<CoreDumpInfo> {
|
||||||
try {
|
try {
|
||||||
|
console.warn('CoreDump: Initializing core dump')
|
||||||
const dump: CoreDumpInfo = await coredump(coreDumpManager)
|
const dump: CoreDumpInfo = await coredump(coreDumpManager)
|
||||||
/* NOTE: this console output of the coredump should include the field
|
/* NOTE: this console output of the coredump should include the field
|
||||||
`github_issue_url` which is not in the uploaded coredump file.
|
`github_issue_url` which is not in the uploaded coredump file.
|
||||||
|
@ -13,6 +13,14 @@ import screenshot from 'lib/screenshot'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { VITE_KC_API_BASE_URL } from 'env'
|
import { VITE_KC_API_BASE_URL } from 'env'
|
||||||
|
|
||||||
|
/* eslint-disable suggest-no-throw/suggest-no-throw --
|
||||||
|
* All the throws in CoreDumpManager are intentional and should be caught and handled properly
|
||||||
|
* by the calling Promises with a catch block. The throws are essential to properly handling
|
||||||
|
* when the app isn't ready enough or otherwise unable to produce a core dump. By throwing
|
||||||
|
* instead of simply erroring, the code halts execution at the first point which it cannot
|
||||||
|
* complete the core dump request.
|
||||||
|
**/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CoreDumpManager module
|
* CoreDumpManager module
|
||||||
* - for getting all the values from the JS world to pass to the Rust world for a core dump.
|
* - for getting all the values from the JS world to pass to the Rust world for a core dump.
|
||||||
@ -22,6 +30,7 @@ import { VITE_KC_API_BASE_URL } from 'env'
|
|||||||
// CoreDumpManager is instantiated in ModelingMachineProvider and passed to coreDump() in wasm.ts
|
// CoreDumpManager is instantiated in ModelingMachineProvider and passed to coreDump() in wasm.ts
|
||||||
// The async function coreDump() handles any errors thrown in its Promise catch method and rethrows
|
// The async function coreDump() handles any errors thrown in its Promise catch method and rethrows
|
||||||
// them to so the toast handler in ModelingMachineProvider can show the user an error message toast
|
// them to so the toast handler in ModelingMachineProvider can show the user an error message toast
|
||||||
|
// TODO: Throw more
|
||||||
export class CoreDumpManager {
|
export class CoreDumpManager {
|
||||||
engineCommandManager: EngineCommandManager
|
engineCommandManager: EngineCommandManager
|
||||||
htmlRef: React.RefObject<HTMLDivElement> | null
|
htmlRef: React.RefObject<HTMLDivElement> | null
|
||||||
|
@ -96,9 +96,7 @@ export function useCalculateKclExpression({
|
|||||||
ast,
|
ast,
|
||||||
engineCommandManager,
|
engineCommandManager,
|
||||||
useFakeExecutor: true,
|
useFakeExecutor: true,
|
||||||
programMemoryOverride: JSON.parse(
|
programMemoryOverride: kclManager.programMemory,
|
||||||
JSON.stringify(kclManager.programMemory)
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
const resultDeclaration = ast.body.find(
|
const resultDeclaration = ast.body.find(
|
||||||
(a) =>
|
(a) =>
|
||||||
|
@ -26,7 +26,11 @@ import {
|
|||||||
applyConstraintEqualLength,
|
applyConstraintEqualLength,
|
||||||
setEqualLengthInfo,
|
setEqualLengthInfo,
|
||||||
} from 'components/Toolbar/EqualLength'
|
} from 'components/Toolbar/EqualLength'
|
||||||
import { addStartProfileAt, extrudeSketch } from 'lang/modifyAst'
|
import {
|
||||||
|
addStartProfileAt,
|
||||||
|
deleteFromSelection,
|
||||||
|
extrudeSketch,
|
||||||
|
} from 'lang/modifyAst'
|
||||||
import { getNodeFromPath } from '../lang/queryAst'
|
import { getNodeFromPath } from '../lang/queryAst'
|
||||||
import {
|
import {
|
||||||
applyConstraintEqualAngle,
|
applyConstraintEqualAngle,
|
||||||
@ -44,12 +48,14 @@ import {
|
|||||||
import { Models } from '@kittycad/lib/dist/types/src'
|
import { Models } from '@kittycad/lib/dist/types/src'
|
||||||
import { ModelingCommandSchema } from 'lib/commandBarConfigs/modelingCommandConfig'
|
import { ModelingCommandSchema } from 'lib/commandBarConfigs/modelingCommandConfig'
|
||||||
import { err, trap } from 'lib/trap'
|
import { err, trap } from 'lib/trap'
|
||||||
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
|
import { DefaultPlaneStr, getFaceDetails } from 'clientSideScene/sceneEntities'
|
||||||
import { Vector3 } from 'three'
|
import { Vector3 } from 'three'
|
||||||
import { quaternionFromUpNForward } from 'clientSideScene/helpers'
|
import { quaternionFromUpNForward } from 'clientSideScene/helpers'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { Coords2d } from 'lang/std/sketch'
|
import { Coords2d } from 'lang/std/sketch'
|
||||||
import { deleteSegment } from 'clientSideScene/ClientSideSceneComp'
|
import { deleteSegment } from 'clientSideScene/ClientSideSceneComp'
|
||||||
|
import { executeAst } from 'useStore'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
|
||||||
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'
|
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'
|
||||||
|
|
||||||
@ -157,6 +163,9 @@ export type ModelingMachineEvent =
|
|||||||
type: 'Set selection'
|
type: 'Set selection'
|
||||||
data: SetSelections
|
data: SetSelections
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'Delete selection'
|
||||||
|
}
|
||||||
| { type: 'Sketch no face' }
|
| { type: 'Sketch no face' }
|
||||||
| { type: 'Toggle gui mode' }
|
| { type: 'Toggle gui mode' }
|
||||||
| { type: 'Cancel' }
|
| { type: 'Cancel' }
|
||||||
@ -273,6 +282,13 @@ export const modelingMachine = createMachine(
|
|||||||
cond: 'Has exportable geometry',
|
cond: 'Has exportable geometry',
|
||||||
actions: 'Engine export',
|
actions: 'Engine export',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'Delete selection': {
|
||||||
|
target: 'idle',
|
||||||
|
cond: 'has valid selection for deletion',
|
||||||
|
actions: ['AST delete selection'],
|
||||||
|
internal: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
entry: 'reset client scene mouse handlers',
|
entry: 'reset client scene mouse handlers',
|
||||||
@ -963,6 +979,42 @@ export const modelingMachine = createMachine(
|
|||||||
editorManager.selectRange(updatedAst?.selections)
|
editorManager.selectRange(updatedAst?.selections)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'AST delete selection': async ({ sketchDetails, selectionRanges }) => {
|
||||||
|
let ast = kclManager.ast
|
||||||
|
|
||||||
|
const getScaledFaceDetails = async (entityId: string) => {
|
||||||
|
const faceDetails = await getFaceDetails(entityId)
|
||||||
|
if (err(faceDetails)) return {}
|
||||||
|
return {
|
||||||
|
...faceDetails,
|
||||||
|
origin: {
|
||||||
|
x: faceDetails.origin.x / sceneInfra._baseUnitMultiplier,
|
||||||
|
y: faceDetails.origin.y / sceneInfra._baseUnitMultiplier,
|
||||||
|
z: faceDetails.origin.z / sceneInfra._baseUnitMultiplier,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const modifiedAst = await deleteFromSelection(
|
||||||
|
ast,
|
||||||
|
selectionRanges.codeBasedSelections[0],
|
||||||
|
kclManager.programMemory,
|
||||||
|
getScaledFaceDetails
|
||||||
|
)
|
||||||
|
if (err(modifiedAst)) return
|
||||||
|
|
||||||
|
const testExecute = await executeAst({
|
||||||
|
ast: modifiedAst,
|
||||||
|
useFakeExecutor: true,
|
||||||
|
engineCommandManager,
|
||||||
|
})
|
||||||
|
if (testExecute.errors.length) {
|
||||||
|
toast.error('Unable to delete part')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await kclManager.updateAst(modifiedAst, true)
|
||||||
|
},
|
||||||
'conditionally equip line tool': (_, { type }) => {
|
'conditionally equip line tool': (_, { type }) => {
|
||||||
if (type === 'done.invoke.animate-to-face') {
|
if (type === 'done.invoke.animate-to-face') {
|
||||||
sceneInfra.modelingSend('Equip Line tool')
|
sceneInfra.modelingSend('Equip Line tool')
|
||||||
|
Reference in New Issue
Block a user