Compare commits

...

4 Commits

Author SHA1 Message Date
33822b5a19 Bump to v0.6.1 (#465) 2023-09-13 06:33:11 -04:00
a2a4daebe3 fix move cmd order (#462) 2023-09-13 07:42:42 +00:00
a17ede50bd Build endpoint for download page on website (#451) 2023-09-13 03:03:13 +00:00
2d452f80d1 ts-rs changes (#450)
* initial changes

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

* updates

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

* fix tests

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

* fixes

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

* updates

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

* bust cache

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

* add dumb shit

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

* Revert "add dumb shit"

This reverts commit 638e9cf72f75e1ad08fb6b22d2a7b143ab7e06e5.

* Revert "bust cache"

This reverts commit fd6f53ba0757d635190aa82d4b055a83755f3027.

* fix

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2023-09-13 11:10:27 +10:00
21 changed files with 172 additions and 180 deletions

View File

@ -1,6 +1,6 @@
VITE_KC_API_WS_MODELING_URL=wss://api.dev.kittycad.io/ws/modeling/commands VITE_KC_API_WS_MODELING_URL=wss://api.kittycad.io/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.dev.kittycad.io VITE_KC_API_BASE_URL=https://api.kittycad.io
VITE_KC_SITE_BASE_URL=https://dev.kittycad.io VITE_KC_SITE_BASE_URL=https://kittycad.io
VITE_KC_SKIP_AUTH=false VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=5000 VITE_KC_CONNECTION_TIMEOUT_MS=15000
VITE_KC_SENTRY_DSN= VITE_KC_SENTRY_DSN=

View File

@ -153,6 +153,8 @@ jobs:
needs: [build-test-web, build-apps] needs: [build-test-web, build-apps]
env: env:
VERSION_NO_V: ${{ needs.build-test-web.outputs.version }} VERSION_NO_V: ${{ needs.build-test-web.outputs.version }}
PUB_DATE: ${{ github.event.release.created_at }}
NOTES: ${{ github.event.release.body }}
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v3
@ -166,6 +168,8 @@ jobs:
RELEASE_DIR=https://dl.kittycad.io/releases/modeling-app/v${VERSION_NO_V} RELEASE_DIR=https://dl.kittycad.io/releases/modeling-app/v${VERSION_NO_V}
jq --null-input \ jq --null-input \
--arg version "v${VERSION_NO_V}" \ --arg version "v${VERSION_NO_V}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg darwin_sig "$DARWIN_SIG" \ --arg darwin_sig "$DARWIN_SIG" \
--arg darwin_url "$RELEASE_DIR/macos/KittyCAD%20Modeling.app.tar.gz" \ --arg darwin_url "$RELEASE_DIR/macos/KittyCAD%20Modeling.app.tar.gz" \
--arg linux_sig "$LINUX_SIG" \ --arg linux_sig "$LINUX_SIG" \
@ -174,6 +178,8 @@ jobs:
--arg windows_url "$RELEASE_DIR/nsis/KittyCAD%20Modeling_${VERSION_NO_V}_x64-setup.nsis.zip" \ --arg windows_url "$RELEASE_DIR/nsis/KittyCAD%20Modeling_${VERSION_NO_V}_x64-setup.nsis.zip" \
'{ '{
"version": $version, "version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": { "platforms": {
"darwin-x86_64": { "darwin-x86_64": {
"signature": $darwin_sig, "signature": $darwin_sig,
@ -195,6 +201,34 @@ jobs:
}' > last_update.json }' > last_update.json
cat last_update.json cat last_update.json
- name: Generate the download static endpoint
run: |
RELEASE_DIR=https://dl.kittycad.io/releases/modeling-app/v${VERSION_NO_V}
jq --null-input \
--arg version "v${VERSION_NO_V}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg darwin_url "$RELEASE_DIR/dmg/KittyCAD%20Modeling_${VERSION_NO_V}_universal.dmg" \
--arg linux_url "$RELEASE_DIR/appimage/kittycad-modeling_${VERSION_NO_V}_amd64.AppImage" \
--arg windows_url "$RELEASE_DIR/msi/KittyCAD%20Modeling_${VERSION_NO_V}_x64_en-US.msi.zip" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"dmg-universal": {
"url": $darwin_url
},
"appimage-x86_64": {
"url": $linux_url
},
"msi-x86_64": {
"url": $windows_url
}
}
}' > last_download.json
cat last_download.json
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v1.1.1' uses: 'google-github-actions/auth@v1.1.1'
with: with:
@ -219,6 +253,12 @@ jobs:
path: last_update.json path: last_update.json
destination: dl.kittycad.io/releases/modeling-app destination: dl.kittycad.io/releases/modeling-app
- name: Upload download endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v1.0.3
with:
path: last_download.json
destination: dl.kittycad.io/releases/modeling-app
- name: Upload release files to Github - name: Upload release files to Github
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:

View File

@ -1,6 +1,6 @@
{ {
"name": "untitled-app", "name": "untitled-app",
"version": "0.6.0", "version": "0.6.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.9.0", "@codemirror/autocomplete": "^6.9.0",

View File

@ -8,7 +8,7 @@
}, },
"package": { "package": {
"productName": "kittycad-modeling", "productName": "kittycad-modeling",
"version": "0.6.0" "version": "0.6.1"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {

View File

@ -192,7 +192,7 @@ export function App() {
start: null, start: null,
}, },
}) })
setProgramMemory({ root: {} }) setProgramMemory({ root: {}, return: null })
engineCommandManager.endSession() engineCommandManager.endSession()
engineCommandManager.startNewSession() engineCommandManager.startNewSession()
return return
@ -209,26 +209,27 @@ export function App() {
{ {
root: { root: {
_0: { _0: {
type: 'userVal', type: 'UserVal',
value: 0, value: 0,
__meta: [], __meta: [],
}, },
_90: { _90: {
type: 'userVal', type: 'UserVal',
value: 90, value: 90,
__meta: [], __meta: [],
}, },
_180: { _180: {
type: 'userVal', type: 'UserVal',
value: 180, value: 180,
__meta: [], __meta: [],
}, },
_270: { _270: {
type: 'userVal', type: 'UserVal',
value: 270, value: 270,
__meta: [], __meta: [],
}, },
}, },
return: null,
}, },
engineCommandManager engineCommandManager
) )
@ -313,18 +314,6 @@ export function App() {
window: { x, y }, window: { x, y },
}, },
}) })
} else if (
guiMode.mode === 'sketch' &&
guiMode.sketchMode === ('move' as any)
) {
debounceSocketSend({
type: 'modeling_cmd_req',
cmd_id: newCmdId,
cmd: {
type: 'handle_mouse_drag_move',
window: { x, y },
},
})
} else { } else {
debounceSocketSend({ debounceSocketSend({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
@ -336,6 +325,17 @@ export function App() {
}) })
} }
} else { } else {
if (guiMode.mode === 'sketch' && guiMode.sketchMode === ('move' as any)) {
debounceSocketSend({
type: 'modeling_cmd_req',
cmd_id: newCmdId,
cmd: {
type: 'handle_mouse_drag_move',
window: { x, y },
},
})
return
}
const interactionGuards = cameraMouseDragGuards[cameraControls] const interactionGuards = cameraMouseDragGuards[cameraControls]
let interaction: CameraDragInteractionType_type let interaction: CameraDragInteractionType_type

View File

@ -144,7 +144,7 @@ export function useCalc({
try { try {
const code = `const __result__ = ${value}\nshow(__result__)` const code = `const __result__ = ${value}\nshow(__result__)`
const ast = parser_wasm(code) const ast = parser_wasm(code)
const _programMem: any = { root: {} } const _programMem: any = { root: {}, return: null }
availableVarInfo.variables.forEach(({ key, value }) => { availableVarInfo.variables.forEach(({ key, value }) => {
_programMem.root[key] = { type: 'userVal', value, __meta: [] } _programMem.root[key] = { type: 'userVal', value, __meta: [] }
}) })

View File

@ -29,6 +29,7 @@ describe('processMemory', () => {
const ast = parser_wasm(code) const ast = parser_wasm(code)
const programMemory = await enginelessExecutor(ast, { const programMemory = await enginelessExecutor(ast, {
root: {}, root: {},
return: null,
}) })
const output = processMemory(programMemory) const output = processMemory(programMemory)
expect(output.myVar).toEqual(5) expect(output.myVar).toEqual(5)

View File

@ -2,7 +2,7 @@ import ReactJson from 'react-json-view'
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel' import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { useMemo } from 'react' import { useMemo } from 'react'
import { ProgramMemory } from '../lang/executor' import { ProgramMemory, Path, ExtrudeSurface } from '../lang/executor'
import { Themes } from '../lib/theme' import { Themes } from '../lib/theme'
interface MemoryPanelProps extends CollapsiblePanelProps { interface MemoryPanelProps extends CollapsiblePanelProps {
@ -49,8 +49,12 @@ export const processMemory = (programMemory: ProgramMemory) => {
Object.keys(programMemory.root).forEach((key) => { Object.keys(programMemory.root).forEach((key) => {
const val = programMemory.root[key] const val = programMemory.root[key]
if (typeof val.value !== 'function') { if (typeof val.value !== 'function') {
if (val.type === 'sketchGroup' || val.type === 'extrudeGroup') { if (val.type === 'SketchGroup') {
processedMemory[key] = val.value.map(({ __geoMeta, ...rest }) => { processedMemory[key] = val.value.map(({ __geoMeta, ...rest }: Path) => {
return rest
})
} else if (val.type === 'ExtrudeGroup') {
processedMemory[key] = val.value.map(({ ...rest }: ExtrudeSurface) => {
return rest return rest
}) })
} else { } else {

View File

@ -21,7 +21,7 @@ show(mySketch001)`
) )
expect(shown).toEqual([ expect(shown).toEqual([
{ {
type: 'sketchGroup', type: 'SketchGroup',
start: { start: {
to: [0, 0], to: [0, 0],
from: [0, 0], from: [0, 0],
@ -77,7 +77,7 @@ show(mySketch001)`
) )
expect(shown).toEqual([ expect(shown).toEqual([
{ {
type: 'extrudeGroup', type: 'ExtrudeGroup',
id: expect.any(String), id: expect.any(String),
value: [], value: [],
height: 2, height: 2,
@ -117,7 +117,7 @@ show(theExtrude, sk2)`
) )
expect(geos).toEqual([ expect(geos).toEqual([
{ {
type: 'extrudeGroup', type: 'ExtrudeGroup',
id: expect.any(String), id: expect.any(String),
value: [], value: [],
height: 2, height: 2,
@ -126,7 +126,7 @@ show(theExtrude, sk2)`
__meta: [{ sourceRange: [13, 34] }], __meta: [{ sourceRange: [13, 34] }],
}, },
{ {
type: 'extrudeGroup', type: 'ExtrudeGroup',
id: expect.any(String), id: expect.any(String),
value: [], value: [],
height: 2, height: 2,

View File

@ -1,7 +1,7 @@
import fs from 'node:fs' import fs from 'node:fs'
import { parser_wasm } from './abstractSyntaxTree' import { parser_wasm } from './abstractSyntaxTree'
import { ProgramMemory } from './executor' import { ProgramMemory, SketchGroup } from './executor'
import { initPromise } from './rust' import { initPromise } from './rust'
import { enginelessExecutor } from '../lib/testHelpers' import { enginelessExecutor } from '../lib/testHelpers'
import { vi } from 'vitest' import { vi } from 'vitest'
@ -117,10 +117,10 @@ show(mySketch)
// ].join('\n') // ].join('\n')
// const { root } = await exe(code) // const { root } = await exe(code)
// expect(root.mySk1.value).toHaveLength(3) // expect(root.mySk1.value).toHaveLength(3)
// expect(root?.rotated?.type).toBe('sketchGroup') // expect(root?.rotated?.type).toBe('SketchGroup')
// if ( // if (
// root?.mySk1?.type !== 'sketchGroup' || // root?.mySk1?.type !== 'SketchGroup' ||
// root?.rotated?.type !== 'sketchGroup' // root?.rotated?.type !== 'SketchGroup'
// ) // )
// throw new Error('not a sketch group') // throw new Error('not a sketch group')
// expect(root.mySk1.rotation).toEqual([0, 0, 0, 1]) // expect(root.mySk1.rotation).toEqual([0, 0, 0, 1])
@ -143,7 +143,7 @@ show(mySketch)
].join('\n') ].join('\n')
const { root } = await exe(code) const { root } = await exe(code)
expect(root.mySk1).toEqual({ expect(root.mySk1).toEqual({
type: 'sketchGroup', type: 'SketchGroup',
start: { start: {
to: [0, 0], to: [0, 0],
from: [0, 0], from: [0, 0],
@ -199,7 +199,7 @@ show(mySketch)
// TODO path to node is probably wrong here, zero indexes are not correct // TODO path to node is probably wrong here, zero indexes are not correct
expect(root).toEqual({ expect(root).toEqual({
three: { three: {
type: 'userVal', type: 'UserVal',
value: 3, value: 3,
__meta: [ __meta: [
{ {
@ -208,7 +208,7 @@ show(mySketch)
], ],
}, },
yo: { yo: {
type: 'userVal', type: 'UserVal',
value: [1, '2', 3, 9], value: [1, '2', 3, 9],
__meta: [ __meta: [
{ {
@ -225,7 +225,7 @@ show(mySketch)
].join('\n') ].join('\n')
const { root } = await exe(code) const { root } = await exe(code)
expect(root.yo).toEqual({ expect(root.yo).toEqual({
type: 'userVal', type: 'UserVal',
value: { aStr: 'str', anum: 2, identifier: 3, binExp: 9 }, value: { aStr: 'str', anum: 2, identifier: 3, binExp: 9 },
__meta: [ __meta: [
{ {
@ -240,7 +240,7 @@ show(mySketch)
) )
const { root } = await exe(code) const { root } = await exe(code)
expect(root.myVar).toEqual({ expect(root.myVar).toEqual({
type: 'userVal', type: 'UserVal',
value: '123', value: '123',
__meta: [ __meta: [
{ {
@ -338,7 +338,7 @@ describe('testing math operators', () => {
const { root } = await exe(code) const { root } = await exe(code)
const sketch = root.part001 const sketch = root.part001
// result of `-legLen(5, min(3, 999))` should be -4 // result of `-legLen(5, min(3, 999))` should be -4
const yVal = sketch.value?.[0]?.to?.[1] const yVal = (sketch as SketchGroup).value?.[0]?.to?.[1]
expect(yVal).toBe(-4) expect(yVal).toBe(-4)
}) })
it('test that % substitution feeds down CallExp->ArrExp->UnaryExp->CallExp', async () => { it('test that % substitution feeds down CallExp->ArrExp->UnaryExp->CallExp', async () => {
@ -356,8 +356,8 @@ describe('testing math operators', () => {
const { root } = await exe(code) const { root } = await exe(code)
const sketch = root.part001 const sketch = root.part001
// expect -legLen(segLen('seg01', %), myVar) to equal -4 setting the y value back to 0 // expect -legLen(segLen('seg01', %), myVar) to equal -4 setting the y value back to 0
expect(sketch.value?.[1]?.from).toEqual([3, 4]) expect((sketch as SketchGroup).value?.[1]?.from).toEqual([3, 4])
expect(sketch.value?.[1]?.to).toEqual([6, 0]) expect((sketch as SketchGroup).value?.[1]?.to).toEqual([6, 0])
const removedUnaryExp = code.replace( const removedUnaryExp = code.replace(
`-legLen(segLen('seg01', %), myVar)`, `-legLen(segLen('seg01', %), myVar)`,
`legLen(segLen('seg01', %), myVar)` `legLen(segLen('seg01', %), myVar)`
@ -366,7 +366,9 @@ describe('testing math operators', () => {
const removedUnaryExpRootSketch = removedUnaryExpRoot.part001 const removedUnaryExpRootSketch = removedUnaryExpRoot.part001
// without the minus sign, the y value should be 8 // without the minus sign, the y value should be 8
expect(removedUnaryExpRootSketch.value?.[1]?.to).toEqual([6, 8]) expect((removedUnaryExpRootSketch as SketchGroup).value?.[1]?.to).toEqual([
6, 8,
])
}) })
it('with nested callExpression and binaryExpression', async () => { it('with nested callExpression and binaryExpression', async () => {
const code = 'const myVar = 2 + min(100, -1 + legLen(5, 3))' const code = 'const myVar = 2 + min(100, -1 + legLen(5, 3))'
@ -397,7 +399,10 @@ show(theExtrude)`
// helpers // helpers
async function exe(code: string, programMemory: ProgramMemory = { root: {} }) { async function exe(
code: string,
programMemory: ProgramMemory = { root: {}, return: null }
) {
const ast = parser_wasm(code) const ast = parser_wasm(code)
const result = await enginelessExecutor(ast, programMemory) const result = await enginelessExecutor(ast, programMemory)

View File

@ -5,96 +5,21 @@ import {
SourceRangeMap, SourceRangeMap,
} from './std/engineConnection' } from './std/engineConnection'
import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn' import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn'
import { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
import { execute_wasm } from '../wasm-lib/pkg/wasm_lib' import { execute_wasm } from '../wasm-lib/pkg/wasm_lib'
import { KCLError } from './errors' import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError' import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { rangeTypeFix } from './abstractSyntaxTree' import { rangeTypeFix } from './abstractSyntaxTree'
export type SourceRange = [number, number] export type { SourceRange } from '../wasm-lib/kcl/bindings/SourceRange'
export type PathToNode = [string | number, string][] // [pathKey, nodeType][] export type { Position } from '../wasm-lib/kcl/bindings/Position'
export type Metadata = { export type { Rotation } from '../wasm-lib/kcl/bindings/Rotation'
sourceRange: SourceRange export type { Path } from '../wasm-lib/kcl/bindings/Path'
} export type { SketchGroup } from '../wasm-lib/kcl/bindings/SketchGroup'
export type Position = [number, number, number] export type { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
export type Rotation = [number, number, number, number] export type { ExtrudeSurface } from '../wasm-lib/kcl/bindings/ExtrudeSurface'
interface BasePath { export type PathToNode = [string | number, string][]
from: [number, number]
to: [number, number]
name?: string
__geoMeta: {
id: string
sourceRange: SourceRange
}
}
export interface ToPoint extends BasePath {
type: 'toPoint'
}
export interface Base extends BasePath {
type: 'base'
}
export interface HorizontalLineTo extends BasePath {
type: 'horizontalLineTo'
x: number
}
export interface AngledLineTo extends BasePath {
type: 'angledLineTo'
angle: number
x?: number
y?: number
}
interface GeoMeta {
__geoMeta: {
id: string
sourceRange: SourceRange
}
}
export type Path = ToPoint | HorizontalLineTo | AngledLineTo | Base
export interface SketchGroup {
type: 'sketchGroup'
id: string
value: Path[]
start?: Base
position: Position
rotation: Rotation
__meta: Metadata[]
}
interface ExtrudePlane {
type: 'extrudePlane'
position: Position
rotation: Rotation
name?: string
}
export type ExtrudeSurface = GeoMeta &
ExtrudePlane /* | ExtrudeRadius | ExtrudeSpline */
export interface ExtrudeGroup {
type: 'extrudeGroup'
id: string
value: ExtrudeSurface[]
height: number
position: Position
rotation: Rotation
__meta: Metadata[]
}
/** UserVal not produced by one of our internal functions */
export interface UserVal {
type: 'userVal'
value: any
__meta: Metadata[]
}
type MemoryItem = UserVal | SketchGroup | ExtrudeGroup
interface Memory { interface Memory {
[key: string]: MemoryItem [key: string]: MemoryItem
@ -102,12 +27,12 @@ interface Memory {
export interface ProgramMemory { export interface ProgramMemory {
root: Memory root: Memory
return?: ProgramReturn return: ProgramReturn | null
} }
export const executor = async ( export const executor = async (
node: Program, node: Program,
programMemory: ProgramMemory = { root: {} }, programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager, engineCommandManager: EngineCommandManager,
// work around while the gemotry is still be stored on the frontend // work around while the gemotry is still be stored on the frontend
// will be removed when the stream UI is added. // will be removed when the stream UI is added.
@ -132,7 +57,7 @@ export const executor = async (
export const _executor = async ( export const _executor = async (
node: Program, node: Program,
programMemory: ProgramMemory = { root: {} }, programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
): Promise<ProgramMemory> => { ): Promise<ProgramMemory> => {
try { try {

View File

@ -770,7 +770,8 @@ export class EngineCommandManager {
if (command.type !== 'modeling_cmd_req') return Promise.resolve() if (command.type !== 'modeling_cmd_req') return Promise.resolve()
const cmd = command.cmd const cmd = command.cmd
if ( if (
cmd.type === 'camera_drag_move' && (cmd.type === 'camera_drag_move' ||
cmd.type === 'handle_mouse_drag_move') &&
this.engineConnection?.unreliableDataChannel this.engineConnection?.unreliableDataChannel
) { ) {
cmd.sequence = this.outSequence cmd.sequence = this.outSequence

View File

@ -4,6 +4,7 @@ import {
SketchGroup, SketchGroup,
SourceRange, SourceRange,
PathToNode, PathToNode,
MemoryItem,
} from '../executor' } from '../executor'
import { import {
Program, Program,
@ -197,7 +198,7 @@ export const line: SketchLineHelper = {
) )
const variableName = varDec.id.name const variableName = varDec.id.name
const sketch = previousProgramMemory?.root?.[variableName] const sketch = previousProgramMemory?.root?.[variableName]
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup') if (sketch.type !== 'SketchGroup') throw new Error('not a SketchGroup')
const newXVal = createLiteral(roundOff(to[0] - from[0], 2)) const newXVal = createLiteral(roundOff(to[0] - from[0], 2))
const newYVal = createLiteral(roundOff(to[1] - from[1], 2)) const newYVal = createLiteral(roundOff(to[1] - from[1], 2))
@ -538,7 +539,7 @@ export const angledLineOfXLength: SketchLineHelper = {
) )
const variableName = varDec.id.name const variableName = varDec.id.name
const sketch = previousProgramMemory?.root?.[variableName] const sketch = previousProgramMemory?.root?.[variableName]
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup') if (sketch.type !== 'SketchGroup') throw new Error('not a SketchGroup')
const angle = createLiteral(roundOff(getAngle(from, to), 0)) const angle = createLiteral(roundOff(getAngle(from, to), 0))
const xLength = createLiteral(roundOff(Math.abs(from[0] - to[0]), 2) || 0.1) const xLength = createLiteral(roundOff(Math.abs(from[0] - to[0]), 2) || 0.1)
const newLine = createCallback const newLine = createCallback
@ -611,7 +612,7 @@ export const angledLineOfYLength: SketchLineHelper = {
) )
const variableName = varDec.id.name const variableName = varDec.id.name
const sketch = previousProgramMemory?.root?.[variableName] const sketch = previousProgramMemory?.root?.[variableName]
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup') if (sketch.type !== 'SketchGroup') throw new Error('not a SketchGroup')
const angle = createLiteral(roundOff(getAngle(from, to), 0)) const angle = createLiteral(roundOff(getAngle(from, to), 0))
const yLength = createLiteral(roundOff(Math.abs(from[1] - to[1]), 2) || 0.1) const yLength = createLiteral(roundOff(Math.abs(from[1] - to[1]), 2) || 0.1)
@ -868,7 +869,7 @@ export const angledLineThatIntersects: SketchLineHelper = {
const varName = varDec.declarations[0].id.name const varName = varDec.declarations[0].id.name
const sketchGroup = previousProgramMemory.root[varName] as SketchGroup const sketchGroup = previousProgramMemory.root[varName] as SketchGroup
const intersectPath = sketchGroup.value.find( const intersectPath = sketchGroup.value.find(
({ name }) => name === intersectTagName ({ name }: Path) => name === intersectTagName
) )
let offset = 0 let offset = 0
if (intersectPath) { if (intersectPath) {
@ -965,7 +966,7 @@ export function addNewSketchLn({
>(node, pathToNode, 'PipeExpression') >(node, pathToNode, 'PipeExpression')
const variableName = varDec.id.name const variableName = varDec.id.name
const sketch = previousProgramMemory?.root?.[variableName] const sketch = previousProgramMemory?.root?.[variableName]
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup') if (sketch.type !== 'SketchGroup') throw new Error('not a SketchGroup')
const last = sketch.value[sketch.value.length - 1] || sketch.start const last = sketch.value[sketch.value.length - 1] || sketch.start
const from = last.to const from = last.to

View File

@ -401,6 +401,11 @@ show(part001)`
programMemory.root['part001'] as SketchGroup, programMemory.root['part001'] as SketchGroup,
[index, index] [index, index]
).segment ).segment
expect(segment).toEqual({ to: [0, 0.04], from: [0, 0.04], name: '' }) expect(segment).toEqual({
to: [0, 0.04],
from: [0, 0.04],
name: '',
type: 'base',
})
}) })
}) })

View File

@ -4,7 +4,7 @@ import {
VariableDeclarator, VariableDeclarator,
CallExpression, CallExpression,
} from '../abstractSyntaxTreeTypes' } from '../abstractSyntaxTreeTypes'
import { SketchGroup, SourceRange } from '../executor' import { SketchGroup, SourceRange, Path } from '../executor'
export function getSketchSegmentFromSourceRange( export function getSketchSegmentFromSourceRange(
sketchGroup: SketchGroup, sketchGroup: SketchGroup,
@ -20,10 +20,10 @@ export function getSketchSegmentFromSourceRange(
startSourceRange[1] >= rangeEnd && startSourceRange[1] >= rangeEnd &&
sketchGroup.start sketchGroup.start
) )
return { segment: sketchGroup.start, index: -1 } return { segment: { ...sketchGroup.start, type: 'base' }, index: -1 }
const lineIndex = sketchGroup.value.findIndex( const lineIndex = sketchGroup.value.findIndex(
({ __geoMeta: { sourceRange } }) => ({ __geoMeta: { sourceRange } }: Path) =>
sourceRange[0] <= rangeStart && sourceRange[1] >= rangeEnd sourceRange[0] <= rangeStart && sourceRange[1] >= rangeEnd
) )
const line = sketchGroup.value[lineIndex] const line = sketchGroup.value[lineIndex]

View File

@ -28,6 +28,7 @@ import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch'
import { PathToNode, ProgramMemory } from '../executor' import { PathToNode, ProgramMemory } from '../executor'
import { getSketchSegmentFromSourceRange } from './sketchConstraints' import { getSketchSegmentFromSourceRange } from './sketchConstraints'
import { getAngle, roundOff, normaliseAngle } from '../../lib/utils' import { getAngle, roundOff, normaliseAngle } from '../../lib/utils'
import { MemoryItem } from 'wasm-lib/kcl/bindings/MemoryItem'
type LineInputsType = type LineInputsType =
| 'xAbsolute' | 'xAbsolute'
@ -1452,7 +1453,7 @@ export function transformAstSketchLines({
const varName = varDec.id.name const varName = varDec.id.name
const sketchGroup = programMemory.root?.[varName] const sketchGroup = programMemory.root?.[varName]
if (!sketchGroup || sketchGroup.type !== 'sketchGroup') if (!sketchGroup || sketchGroup.type !== 'SketchGroup')
throw new Error('not a sketch group') throw new Error('not a sketch group')
const seg = getSketchSegmentFromSourceRange(sketchGroup, range).segment const seg = getSketchSegmentFromSourceRange(sketchGroup, range).segment
const referencedSegment = referencedSegmentRange const referencedSegment = referencedSegmentRange

View File

@ -49,7 +49,7 @@ class MockEngineCommandManager {
export async function enginelessExecutor( export async function enginelessExecutor(
ast: Program, ast: Program,
pm: ProgramMemory = { root: {} } pm: ProgramMemory = { root: {}, return: null }
): Promise<ProgramMemory> { ): Promise<ProgramMemory> {
const mockEngineCommandManager = new MockEngineCommandManager({ const mockEngineCommandManager = new MockEngineCommandManager({
setIsStreamReady: () => {}, setIsStreamReady: () => {},
@ -64,7 +64,7 @@ export async function enginelessExecutor(
export async function executor( export async function executor(
ast: Program, ast: Program,
pm: ProgramMemory = { root: {} } pm: ProgramMemory = { root: {}, return: null }
): Promise<ProgramMemory> { ): Promise<ProgramMemory> {
const engineCommandManager = new EngineCommandManager({ const engineCommandManager = new EngineCommandManager({
setIsStreamReady: () => {}, setIsStreamReady: () => {},

View File

@ -360,7 +360,7 @@ export const useStore = create<StoreState>()(
setError: (error = '') => { setError: (error = '') => {
set({ errorState: { isError: !!error, error } }) set({ errorState: { isError: !!error, error } })
}, },
programMemory: { root: {}, pendingMemory: {} }, programMemory: { root: {}, return: null },
setProgramMemory: (programMemory) => set({ programMemory }), setProgramMemory: (programMemory) => set({ programMemory }),
isShiftDown: false, isShiftDown: false,
setIsShiftDown: (isShiftDown) => set({ isShiftDown }), setIsShiftDown: (isShiftDown) => set({ isShiftDown }),

View File

@ -12,7 +12,7 @@ use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, R
use crate::{ use crate::{
engine::EngineConnection, engine::EngineConnection,
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange}, executor::{MemoryItem, Metadata, PipeInfo, ProgramMemory, SourceRange, UserVal},
parser::PIPE_OPERATOR, parser::PIPE_OPERATOR,
}; };
@ -1082,23 +1082,23 @@ impl Literal {
impl From<Literal> for MemoryItem { impl From<Literal> for MemoryItem {
fn from(literal: Literal) -> Self { fn from(literal: Literal) -> Self {
MemoryItem::UserVal { MemoryItem::UserVal(UserVal {
value: literal.value.clone(), value: literal.value.clone(),
meta: vec![Metadata { meta: vec![Metadata {
source_range: literal.into(), source_range: literal.into(),
}], }],
} })
} }
} }
impl From<&Box<Literal>> for MemoryItem { impl From<&Box<Literal>> for MemoryItem {
fn from(literal: &Box<Literal>) -> Self { fn from(literal: &Box<Literal>) -> Self {
MemoryItem::UserVal { MemoryItem::UserVal(UserVal {
value: literal.value.clone(), value: literal.value.clone(),
meta: vec![Metadata { meta: vec![Metadata {
source_range: literal.into(), source_range: literal.into(),
}], }],
} })
} }
} }
@ -1245,12 +1245,12 @@ impl ArrayExpression {
results.push(result); results.push(result);
} }
Ok(MemoryItem::UserVal { Ok(MemoryItem::UserVal(UserVal {
value: results.into(), value: results.into(),
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.into(), source_range: self.into(),
}], }],
}) }))
} }
/// Rename all identifiers that have the old name to the new given name. /// Rename all identifiers that have the old name to the new given name.
@ -1370,12 +1370,12 @@ impl ObjectExpression {
object.insert(property.key.name.clone(), result.get_json_value()?); object.insert(property.key.name.clone(), result.get_json_value()?);
} }
Ok(MemoryItem::UserVal { Ok(MemoryItem::UserVal(UserVal {
value: object.into(), value: object.into(),
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.into(), source_range: self.into(),
}], }],
}) }))
} }
/// Rename all identifiers that have the old name to the new given name. /// Rename all identifiers that have the old name to the new given name.
@ -1582,12 +1582,12 @@ impl MemberExpression {
if let serde_json::Value::Object(map) = object { if let serde_json::Value::Object(map) = object {
if let Some(value) = map.get(&property_name) { if let Some(value) = map.get(&property_name) {
Ok(MemoryItem::UserVal { Ok(MemoryItem::UserVal(UserVal {
value: value.clone(), value: value.clone(),
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.into(), source_range: self.into(),
}], }],
}) }))
} else { } else {
Err(KclError::UndefinedValue(KclErrorDetails { Err(KclError::UndefinedValue(KclErrorDetails {
message: format!("Property {} not found in object", property_name), message: format!("Property {} not found in object", property_name),
@ -1715,12 +1715,12 @@ impl BinaryExpression {
parse_json_value_as_string(&right_json_value), parse_json_value_as_string(&right_json_value),
) { ) {
let value = serde_json::Value::String(format!("{}{}", left, right)); let value = serde_json::Value::String(format!("{}{}", left, right));
return Ok(MemoryItem::UserVal { return Ok(MemoryItem::UserVal(UserVal {
value, value,
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.into(), source_range: self.into(),
}], }],
}); }));
} }
} }
@ -1735,12 +1735,12 @@ impl BinaryExpression {
BinaryOperator::Mod => (left % right).into(), BinaryOperator::Mod => (left % right).into(),
}; };
Ok(MemoryItem::UserVal { Ok(MemoryItem::UserVal(UserVal {
value, value,
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.into(), source_range: self.into(),
}], }],
}) }))
} }
/// Rename all identifiers that have the old name to the new given name. /// Rename all identifiers that have the old name to the new given name.
@ -1845,12 +1845,12 @@ impl UnaryExpression {
.get_json_value()?, .get_json_value()?,
self.into(), self.into(),
)?; )?;
Ok(MemoryItem::UserVal { Ok(MemoryItem::UserVal(UserVal {
value: (-(num)).into(), value: (-(num)).into(),
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.into(), source_range: self.into(),
}], }],
}) }))
} }
/// Returns a hover value that includes the given character position. /// Returns a hover value that includes the given character position.

View File

@ -98,16 +98,14 @@ impl ProgramReturn {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")] #[serde(tag = "type")]
pub enum MemoryItem { pub enum MemoryItem {
UserVal { UserVal(UserVal),
value: serde_json::Value,
#[serde(rename = "__meta")]
meta: Vec<Metadata>,
},
SketchGroup(SketchGroup), SketchGroup(SketchGroup),
ExtrudeGroup(ExtrudeGroup), ExtrudeGroup(ExtrudeGroup),
#[ts(skip)]
ExtrudeTransform(ExtrudeTransform), ExtrudeTransform(ExtrudeTransform),
#[ts(skip)]
Function { Function {
#[serde(skip)] #[serde(skip)]
func: Option<MemoryFunction>, func: Option<MemoryFunction>,
@ -119,7 +117,16 @@ pub enum MemoryItem {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]
pub struct UserVal {
pub value: serde_json::Value,
#[serde(rename = "__meta")]
pub meta: Vec<Metadata>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")]
pub struct ExtrudeTransform { pub struct ExtrudeTransform {
pub position: Position, pub position: Position,
pub rotation: Rotation, pub rotation: Rotation,
@ -138,7 +145,7 @@ pub type MemoryFunction = fn(
impl From<MemoryItem> for Vec<SourceRange> { impl From<MemoryItem> for Vec<SourceRange> {
fn from(item: MemoryItem) -> Self { fn from(item: MemoryItem) -> Self {
match item { match item {
MemoryItem::UserVal { meta, .. } => meta.iter().map(|m| m.source_range).collect(), MemoryItem::UserVal(u) => u.meta.iter().map(|m| m.source_range).collect(),
MemoryItem::SketchGroup(s) => s.meta.iter().map(|m| m.source_range).collect(), MemoryItem::SketchGroup(s) => s.meta.iter().map(|m| m.source_range).collect(),
MemoryItem::ExtrudeGroup(e) => e.meta.iter().map(|m| m.source_range).collect(), MemoryItem::ExtrudeGroup(e) => e.meta.iter().map(|m| m.source_range).collect(),
MemoryItem::ExtrudeTransform(e) => e.meta.iter().map(|m| m.source_range).collect(), MemoryItem::ExtrudeTransform(e) => e.meta.iter().map(|m| m.source_range).collect(),
@ -149,8 +156,8 @@ impl From<MemoryItem> for Vec<SourceRange> {
impl MemoryItem { impl MemoryItem {
pub fn get_json_value(&self) -> Result<serde_json::Value, KclError> { pub fn get_json_value(&self) -> Result<serde_json::Value, KclError> {
if let MemoryItem::UserVal { value, .. } = self { if let MemoryItem::UserVal(user_val) = self {
Ok(value.clone()) Ok(user_val.value.clone())
} else { } else {
Err(KclError::Semantic(KclErrorDetails { Err(KclError::Semantic(KclErrorDetails {
message: format!("Not a user value: {:?}", self), message: format!("Not a user value: {:?}", self),
@ -186,7 +193,7 @@ impl MemoryItem {
/// A sketch group is a collection of paths. /// A sketch group is a collection of paths.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]
pub struct SketchGroup { pub struct SketchGroup {
/// The id of the sketch group. /// The id of the sketch group.
pub id: uuid::Uuid, pub id: uuid::Uuid,
@ -238,7 +245,7 @@ impl SketchGroup {
/// An extrude group is a collection of extrude surfaces. /// An extrude group is a collection of extrude surfaces.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(tag = "type", rename_all = "camelCase")]
pub struct ExtrudeGroup { pub struct ExtrudeGroup {
/// The id of the extrude group. /// The id of the extrude group.
pub id: uuid::Uuid, pub id: uuid::Uuid,
@ -276,15 +283,15 @@ pub enum BodyType {
#[derive(Debug, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema)] #[derive(Debug, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
pub struct Position(pub [f64; 3]); pub struct Position(#[ts(type = "[number, number, number]")] pub [f64; 3]);
#[derive(Debug, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema)] #[derive(Debug, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
pub struct Rotation(pub [f64; 4]); pub struct Rotation(#[ts(type = "[number, number, number, number]")] pub [f64; 4]);
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema, Hash, Eq)] #[derive(Debug, Default, Deserialize, Serialize, PartialEq, Copy, Clone, ts_rs::TS, JsonSchema, Hash, Eq)]
#[ts(export)] #[ts(export)]
pub struct SourceRange(pub [usize; 2]); pub struct SourceRange(#[ts(type = "[number, number]")] pub [usize; 2]);
impl SourceRange { impl SourceRange {
/// Create a new source range. /// Create a new source range.
@ -401,8 +408,10 @@ impl From<SourceRange> for Metadata {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct BasePath { pub struct BasePath {
/// The from point. /// The from point.
#[ts(type = "[number, number]")]
pub from: [f64; 2], pub from: [f64; 2],
/// The to point. /// The to point.
#[ts(type = "[number, number]")]
pub to: [f64; 2], pub to: [f64; 2],
/// The name of the path. /// The name of the path.
pub name: String, pub name: String,

View File

@ -103,12 +103,12 @@ impl<'a> Args<'a> {
} }
fn make_user_val_from_json(&self, j: serde_json::Value) -> Result<MemoryItem, KclError> { fn make_user_val_from_json(&self, j: serde_json::Value) -> Result<MemoryItem, KclError> {
Ok(MemoryItem::UserVal { Ok(MemoryItem::UserVal(crate::executor::UserVal {
value: j, value: j,
meta: vec![Metadata { meta: vec![Metadata {
source_range: self.source_range, source_range: self.source_range,
}], }],
}) }))
} }
fn make_user_val_from_f64(&self, f: f64) -> Result<MemoryItem, KclError> { fn make_user_val_from_f64(&self, f: f64) -> Result<MemoryItem, KclError> {