Compare commits
22 Commits
franknoiro
...
achalmers/
| Author | SHA1 | Date | |
|---|---|---|---|
| c3ac4d085e | |||
| f60a06dffc | |||
| 19f11fe55a | |||
| f6f1574982 | |||
| 6dc4fbc808 | |||
| 8843d02380 | |||
| 3578ec07e6 | |||
| db35f73e41 | |||
| 5cfc2b7941 | |||
| 318e4a0cc7 | |||
| 1e23be8f08 | |||
| ef547e7db8 | |||
| 71b48bbd89 | |||
| c825eac27e | |||
| 82e8a491c4 | |||
| 93e806fc99 | |||
| f1a14f1e3d | |||
| 57c01ec3a2 | |||
| ce951d7c12 | |||
| 0aa2a6cee7 | |||
| ba8f5d9785 | |||
| 50a133b2fa |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -84,7 +84,7 @@ jobs:
|
|||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'schedule'
|
||||||
run: |
|
run: |
|
||||||
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
|
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
|
||||||
echo "$(jq --arg url 'https://dl.kittycad.io/releases/modeling-app/test/nightly/last_update.json' \
|
echo "$(jq --arg url 'https://dl.kittycad.io/releases/modeling-app/nightly/last_update.json' \
|
||||||
'.tauri.updater.endpoints[]=$url' src-tauri/tauri.conf.json --indent 2)" > src-tauri/tauri.conf.json
|
'.tauri.updater.endpoints[]=$url' src-tauri/tauri.conf.json --indent 2)" > src-tauri/tauri.conf.json
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
|
|||||||
@ -3812,7 +3812,7 @@
|
|||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
"name": "data",
|
"name": "data",
|
||||||
"type": "AngeledLineThatIntersectsData",
|
"type": "AngledLineThatIntersectsData",
|
||||||
"schema": {
|
"schema": {
|
||||||
"description": "Data for drawing an angled line that intersects with a given line.",
|
"description": "Data for drawing an angled line that intersects with a given line.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
@ -763,12 +763,12 @@ Draw an angled line that intersects with a given line.
|
|||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
angledLineThatIntersects(data: AngeledLineThatIntersectsData, sketch_group: SketchGroup) -> SketchGroup
|
angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: SketchGroup) -> SketchGroup
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
|
|
||||||
* `data`: `AngeledLineThatIntersectsData` - Data for drawing an angled line that intersects with a given line.
|
* `data`: `AngledLineThatIntersectsData` - Data for drawing an angled line that intersects with a given line.
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
// The angle of the line.
|
// The angle of the line.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.10.0",
|
"version": "0.11.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.9.0",
|
"@codemirror/autocomplete": "^6.9.0",
|
||||||
@ -10,7 +10,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@headlessui/react": "^1.7.13",
|
"@headlessui/react": "^1.7.13",
|
||||||
"@headlessui/tailwindcss": "^0.2.0",
|
"@headlessui/tailwindcss": "^0.2.0",
|
||||||
"@kittycad/lib": "^0.0.43",
|
"@kittycad/lib": "^0.0.45",
|
||||||
"@lezer/javascript": "^1.4.7",
|
"@lezer/javascript": "^1.4.7",
|
||||||
"@open-rpc/client-js": "^1.8.1",
|
"@open-rpc/client-js": "^1.8.1",
|
||||||
"@react-hook/resize-observer": "^1.2.6",
|
"@react-hook/resize-observer": "^1.2.6",
|
||||||
|
|||||||
43
src-tauri/Cargo.lock
generated
43
src-tauri/Cargo.lock
generated
@ -122,6 +122,12 @@ dependencies = [
|
|||||||
"system-deps 6.1.0",
|
"system-deps 6.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1658,9 +1664,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad"
|
name = "kittycad"
|
||||||
version = "0.2.33"
|
version = "0.2.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d341a81a4dfef43460d395c87d86c17e24affb96db0e7f4a35e8688f0e092344"
|
checksum = "633a728fb7209b398b7fa5b67460cb7f3cdb268c6b2a9e81967dda464cfbb5c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -2833,9 +2839,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.20"
|
version = "0.11.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.2",
|
"base64 0.21.2",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -2862,6 +2868,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
@ -3011,9 +3018,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.37.19"
|
version = "0.37.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
|
checksum = "84f3f8f960ed3b5a59055428714943298bf3fa2d4a1d53135084e0544829d995"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"errno",
|
"errno",
|
||||||
@ -3600,6 +3607,27 @@ dependencies = [
|
|||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"system-configuration-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "5.0.0"
|
version = "5.0.0"
|
||||||
@ -3927,7 +3955,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"redox_syscall 0.3.5",
|
"redox_syscall 0.3.5",
|
||||||
"rustix 0.37.19",
|
"rustix 0.37.26",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4292,6 +4320,7 @@ version = "1.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
|
checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atomic",
|
||||||
"getrandom 0.2.9",
|
"getrandom 0.2.9",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "kittycad-modeling",
|
"productName": "kittycad-modeling",
|
||||||
"version": "0.10.0"
|
"version": "0.11.1"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import {
|
|||||||
} from './lib/tauriFS'
|
} from './lib/tauriFS'
|
||||||
import { metadata, type Metadata } from 'tauri-plugin-fs-extra-api'
|
import { metadata, type Metadata } from 'tauri-plugin-fs-extra-api'
|
||||||
import DownloadAppBanner from './components/DownloadAppBanner'
|
import DownloadAppBanner from './components/DownloadAppBanner'
|
||||||
|
import { WasmErrBanner } from './components/WasmErrBanner'
|
||||||
import { GlobalStateProvider } from './components/GlobalStateProvider'
|
import { GlobalStateProvider } from './components/GlobalStateProvider'
|
||||||
import {
|
import {
|
||||||
SETTINGS_PERSIST_KEY,
|
SETTINGS_PERSIST_KEY,
|
||||||
@ -43,6 +44,7 @@ import * as Sentry from '@sentry/react'
|
|||||||
import ModelingMachineProvider from 'components/ModelingMachineProvider'
|
import ModelingMachineProvider from 'components/ModelingMachineProvider'
|
||||||
import { KclContextProvider } from 'lang/KclSinglton'
|
import { KclContextProvider } from 'lang/KclSinglton'
|
||||||
import FileMachineProvider from 'components/FileMachineProvider'
|
import FileMachineProvider from 'components/FileMachineProvider'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
if (VITE_KC_SENTRY_DSN && !TEST) {
|
if (VITE_KC_SENTRY_DSN && !TEST) {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
@ -144,12 +146,13 @@ const router = createBrowserRouter(
|
|||||||
path: paths.FILE + '/:id',
|
path: paths.FILE + '/:id',
|
||||||
element: (
|
element: (
|
||||||
<Auth>
|
<Auth>
|
||||||
<Outlet />
|
|
||||||
<FileMachineProvider>
|
<FileMachineProvider>
|
||||||
<KclContextProvider>
|
<KclContextProvider>
|
||||||
<ModelingMachineProvider>
|
<ModelingMachineProvider>
|
||||||
|
<Outlet />
|
||||||
<App />
|
<App />
|
||||||
</ModelingMachineProvider>
|
</ModelingMachineProvider>
|
||||||
|
<WasmErrBanner />
|
||||||
</KclContextProvider>
|
</KclContextProvider>
|
||||||
</FileMachineProvider>
|
</FileMachineProvider>
|
||||||
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />}
|
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />}
|
||||||
@ -185,23 +188,23 @@ const router = createBrowserRouter(
|
|||||||
|
|
||||||
if (params.id && params.id !== BROWSER_FILE_NAME) {
|
if (params.id && params.id !== BROWSER_FILE_NAME) {
|
||||||
const decodedId = decodeURIComponent(params.id)
|
const decodedId = decodeURIComponent(params.id)
|
||||||
const projectAndFile = decodedId.replace(defaultDir + '/', '')
|
const projectAndFile = decodedId.replace(defaultDir + sep, '')
|
||||||
const firstSlashIndex = projectAndFile.indexOf('/')
|
const firstSlashIndex = projectAndFile.indexOf(sep)
|
||||||
const projectName = projectAndFile.slice(0, firstSlashIndex)
|
const projectName = projectAndFile.slice(0, firstSlashIndex)
|
||||||
const projectPath = defaultDir + '/' + projectName
|
const projectPath = defaultDir + sep + projectName
|
||||||
const currentFileName = projectAndFile.slice(firstSlashIndex + 1)
|
const currentFileName = projectAndFile.slice(firstSlashIndex + 1)
|
||||||
|
|
||||||
if (firstSlashIndex === -1 || !currentFileName)
|
if (firstSlashIndex === -1 || !currentFileName)
|
||||||
return redirect(
|
return redirect(
|
||||||
`${paths.FILE}/${encodeURIComponent(
|
`${paths.FILE}/${encodeURIComponent(
|
||||||
`${params.id}/${PROJECT_ENTRYPOINT}`
|
`${params.id}${sep}${PROJECT_ENTRYPOINT}`
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
|
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
|
||||||
const code = await readTextFile(decodedId)
|
const code = await readTextFile(decodedId)
|
||||||
const entrypointMetadata = await metadata(
|
const entrypointMetadata = await metadata(
|
||||||
projectPath + '/' + PROJECT_ENTRYPOINT
|
projectPath + sep + PROJECT_ENTRYPOINT
|
||||||
)
|
)
|
||||||
const children = await readDir(projectPath, { recursive: true })
|
const children = await readDir(projectPath, { recursive: true })
|
||||||
|
|
||||||
@ -268,9 +271,9 @@ const router = createBrowserRouter(
|
|||||||
isProjectDirectory
|
isProjectDirectory
|
||||||
)
|
)
|
||||||
const projects = await Promise.all(
|
const projects = await Promise.all(
|
||||||
projectsNoMeta.map(async (p) => ({
|
projectsNoMeta.map(async (p: FileEntry) => ({
|
||||||
entrypointMetadata: await metadata(
|
entrypointMetadata: await metadata(
|
||||||
p.path + '/' + PROJECT_ENTRYPOINT
|
p.path + sep + PROJECT_ENTRYPOINT
|
||||||
),
|
),
|
||||||
...p,
|
...p,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -32,13 +32,11 @@ export const AppHeader = ({
|
|||||||
className
|
className
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{project && (
|
<ProjectSidebarMenu
|
||||||
<ProjectSidebarMenu
|
renderAsLink={!enableMenu}
|
||||||
renderAsLink={!enableMenu}
|
project={project?.project}
|
||||||
project={project.project}
|
file={project?.file}
|
||||||
file={project.file}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{/* Toolbar if the context deems it */}
|
{/* Toolbar if the context deems it */}
|
||||||
{showToolbar && (
|
{showToolbar && (
|
||||||
<div className="max-w-lg md:max-w-xl lg:max-w-2xl xl:max-w-4xl 2xl:max-w-5xl">
|
<div className="max-w-lg md:max-w-xl lg:max-w-2xl xl:max-w-4xl 2xl:max-w-5xl">
|
||||||
@ -47,7 +45,7 @@ export const AppHeader = ({
|
|||||||
)}
|
)}
|
||||||
{/* If there are children, show them, otherwise show User menu */}
|
{/* If there are children, show them, otherwise show User menu */}
|
||||||
{children || (
|
{children || (
|
||||||
<div className="ml-auto flex items-center gap-1">
|
<div className="flex items-center gap-1 ml-auto">
|
||||||
<NetworkHealthIndicator />
|
<NetworkHealthIndicator />
|
||||||
<UserSidebarMenu user={user} />
|
<UserSidebarMenu user={user} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
} from '@tauri-apps/api/fs'
|
} from '@tauri-apps/api/fs'
|
||||||
import { FILE_EXT, readProject } from 'lib/tauriFS'
|
import { FILE_EXT, readProject } from 'lib/tauriFS'
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
@ -56,7 +57,7 @@ export const FileMachineProvider = ({
|
|||||||
setCommandBarOpen(false)
|
setCommandBarOpen(false)
|
||||||
navigate(
|
navigate(
|
||||||
`${paths.FILE}/${encodeURIComponent(
|
`${paths.FILE}/${encodeURIComponent(
|
||||||
context.selectedDirectory + '/' + event.data.name
|
context.selectedDirectory + sep + event.data.name
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -82,11 +83,11 @@ export const FileMachineProvider = ({
|
|||||||
let name = event.data.name.trim() || DEFAULT_FILE_NAME
|
let name = event.data.name.trim() || DEFAULT_FILE_NAME
|
||||||
|
|
||||||
if (event.data.makeDir) {
|
if (event.data.makeDir) {
|
||||||
await createDir(context.selectedDirectory.path + '/' + name)
|
await createDir(context.selectedDirectory.path + sep + name)
|
||||||
} else {
|
} else {
|
||||||
await writeFile(
|
await writeFile(
|
||||||
context.selectedDirectory.path +
|
context.selectedDirectory.path +
|
||||||
'/' +
|
sep +
|
||||||
name +
|
name +
|
||||||
(name.endsWith(FILE_EXT) ? '' : FILE_EXT),
|
(name.endsWith(FILE_EXT) ? '' : FILE_EXT),
|
||||||
''
|
''
|
||||||
@ -103,9 +104,9 @@ export const FileMachineProvider = ({
|
|||||||
let name = newName ? newName : DEFAULT_FILE_NAME
|
let name = newName ? newName : DEFAULT_FILE_NAME
|
||||||
|
|
||||||
await renameFile(
|
await renameFile(
|
||||||
context.selectedDirectory.path + '/' + oldName,
|
context.selectedDirectory.path + sep + oldName,
|
||||||
context.selectedDirectory.path +
|
context.selectedDirectory.path +
|
||||||
'/' +
|
sep +
|
||||||
name +
|
name +
|
||||||
(name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT)
|
(name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -24,9 +24,7 @@ import {
|
|||||||
StateFrom,
|
StateFrom,
|
||||||
} from 'xstate'
|
} from 'xstate'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { invoke } from '@tauri-apps/api'
|
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
import { VITE_KC_API_BASE_URL } from 'env'
|
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
|
|||||||
@ -172,27 +172,38 @@ export const ModelingMachineProvider = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'AST add line segment': (
|
'AST add line segment': async (
|
||||||
{ sketchPathToNode, sketchEnginePathId },
|
{ sketchPathToNode, sketchEnginePathId },
|
||||||
{ data: { coords, segmentId } }
|
{ data: { coords, segmentId } }
|
||||||
) => {
|
) => {
|
||||||
if (!sketchPathToNode) return
|
if (!sketchPathToNode) return
|
||||||
const lastCoord = coords[coords.length - 1]
|
const lastCoord = coords[coords.length - 1]
|
||||||
|
|
||||||
const { node: varDec } = getNodeFromPath<VariableDeclarator>(
|
const pathInfo = await engineCommandManager.sendSceneCommand({
|
||||||
kclManager.ast,
|
type: 'modeling_cmd_req',
|
||||||
sketchPathToNode,
|
cmd_id: uuidv4(),
|
||||||
'VariableDeclarator'
|
cmd: {
|
||||||
|
type: 'path_get_info',
|
||||||
|
path_id: sketchEnginePathId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const firstSegment = pathInfo?.data?.data?.segments.find(
|
||||||
|
(seg: any) => seg.command === 'line_to'
|
||||||
)
|
)
|
||||||
const variableName = varDec.id.name
|
const firstSegCoords = await engineCommandManager.sendSceneCommand({
|
||||||
const sketchGroup = kclManager.programMemory.root[variableName]
|
type: 'modeling_cmd_req',
|
||||||
if (!sketchGroup || sketchGroup.type !== 'SketchGroup') return
|
cmd_id: uuidv4(),
|
||||||
const initialCoords = sketchGroup.value[0].from
|
cmd: {
|
||||||
|
type: 'curve_get_control_points',
|
||||||
|
curve_id: firstSegment.command_id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const startPathCoord = firstSegCoords?.data?.data?.control_points[0]
|
||||||
|
|
||||||
const isClose = compareVec2Epsilon(initialCoords, [
|
const isClose = compareVec2Epsilon(
|
||||||
lastCoord.x,
|
[startPathCoord.x, startPathCoord.y],
|
||||||
lastCoord.y,
|
[lastCoord.x, lastCoord.y]
|
||||||
])
|
)
|
||||||
|
|
||||||
let _modifiedAst: Program
|
let _modifiedAst: Program
|
||||||
if (!isClose) {
|
if (!isClose) {
|
||||||
@ -200,6 +211,7 @@ export const ModelingMachineProvider = ({
|
|||||||
node: kclManager.ast,
|
node: kclManager.ast,
|
||||||
programMemory: kclManager.programMemory,
|
programMemory: kclManager.programMemory,
|
||||||
to: [lastCoord.x, lastCoord.y],
|
to: [lastCoord.x, lastCoord.y],
|
||||||
|
from: [coords[0].x, coords[0].y],
|
||||||
fnName: 'line',
|
fnName: 'line',
|
||||||
pathToNode: sketchPathToNode,
|
pathToNode: sketchPathToNode,
|
||||||
})
|
})
|
||||||
@ -413,6 +425,12 @@ export const ModelingMachineProvider = ({
|
|||||||
})
|
})
|
||||||
}, [modelingSend, modelingState.nextEvents])
|
}, [modelingSend, modelingState.nextEvents])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
kclManager.registerExecuteCallback(() => {
|
||||||
|
modelingSend({ type: 'Re-execute' })
|
||||||
|
})
|
||||||
|
}, [modelingSend])
|
||||||
|
|
||||||
// useStateMachineCommands({
|
// useStateMachineCommands({
|
||||||
// state: settingsState,
|
// state: settingsState,
|
||||||
// send: settingsSend,
|
// send: settingsSend,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { Link } from 'react-router-dom'
|
|||||||
import { ExportButton } from './ExportButton'
|
import { ExportButton } from './ExportButton'
|
||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
import { FileTree } from './FileTree'
|
import { FileTree } from './FileTree'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
const ProjectSidebarMenu = ({
|
const ProjectSidebarMenu = ({
|
||||||
project,
|
project,
|
||||||
@ -26,10 +27,10 @@ const ProjectSidebarMenu = ({
|
|||||||
<img
|
<img
|
||||||
src="/kitt-8bit-winking.svg"
|
src="/kitt-8bit-winking.svg"
|
||||||
alt="KittyCAD App"
|
alt="KittyCAD App"
|
||||||
className="h-9 w-auto"
|
className="w-auto h-9"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap hidden lg:block"
|
className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
|
||||||
data-testid="project-sidebar-link-name"
|
data-testid="project-sidebar-link-name"
|
||||||
>
|
>
|
||||||
{project?.name ? project.name : 'KittyCAD Modeling App'}
|
{project?.name ? project.name : 'KittyCAD Modeling App'}
|
||||||
@ -44,16 +45,16 @@ const ProjectSidebarMenu = ({
|
|||||||
<img
|
<img
|
||||||
src="/kitt-8bit-winking.svg"
|
src="/kitt-8bit-winking.svg"
|
||||||
alt="KittyCAD App"
|
alt="KittyCAD App"
|
||||||
className="h-full w-auto"
|
className="w-auto h-full"
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col items-start py-0.5">
|
<div className="flex flex-col items-start py-0.5">
|
||||||
<span className="text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap hidden lg:block">
|
<span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block">
|
||||||
{isTauri() && file?.name
|
{isTauri() && file?.name
|
||||||
? file.name.slice(file.name.lastIndexOf('/') + 1)
|
? file.name.slice(file.name.lastIndexOf(sep) + 1)
|
||||||
: 'KittyCAD Modeling App'}
|
: 'KittyCAD Modeling App'}
|
||||||
</span>
|
</span>
|
||||||
{isTauri() && project?.name && (
|
{isTauri() && project?.name && (
|
||||||
<span className="text-xs text-chalkboard-70 dark:text-chalkboard-40 whitespace-nowrap hidden lg:block">
|
<span className="hidden text-xs text-chalkboard-70 dark:text-chalkboard-40 whitespace-nowrap lg:block">
|
||||||
{project.name}
|
{project.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@ -68,7 +69,7 @@ const ProjectSidebarMenu = ({
|
|||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
>
|
>
|
||||||
<Popover.Overlay className="fixed z-20 inset-0 bg-chalkboard-110/50" />
|
<Popover.Overlay className="fixed inset-0 z-20 bg-chalkboard-110/50" />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
@ -81,7 +82,7 @@ const ProjectSidebarMenu = ({
|
|||||||
as={Fragment}
|
as={Fragment}
|
||||||
>
|
>
|
||||||
<Popover.Panel
|
<Popover.Panel
|
||||||
className="fixed inset-0 right-auto z-30 w-64 h-screen max-h-screen grid grid-cols-1 bg-chalkboard-10 dark:bg-chalkboard-100 border border-energy-100 dark:border-energy-100/50 shadow-md rounded-r-lg"
|
className="fixed inset-0 right-auto z-30 grid w-64 h-screen max-h-screen grid-cols-1 border rounded-r-lg shadow-md bg-chalkboard-10 dark:bg-chalkboard-100 border-energy-100 dark:border-energy-100/50"
|
||||||
style={{ gridTemplateRows: 'auto 1fr auto' }}
|
style={{ gridTemplateRows: 'auto 1fr auto' }}
|
||||||
>
|
>
|
||||||
{({ close }) => (
|
{({ close }) => (
|
||||||
@ -90,7 +91,7 @@ const ProjectSidebarMenu = ({
|
|||||||
<img
|
<img
|
||||||
src="/kitt-8bit-winking.svg"
|
src="/kitt-8bit-winking.svg"
|
||||||
alt="KittyCAD App"
|
alt="KittyCAD App"
|
||||||
className="h-9 w-auto"
|
className="w-auto h-9"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -102,7 +103,7 @@ const ProjectSidebarMenu = ({
|
|||||||
</p>
|
</p>
|
||||||
{project?.entrypointMetadata && (
|
{project?.entrypointMetadata && (
|
||||||
<p
|
<p
|
||||||
className="m-0 text-chalkboard-100 dark:text-energy-40 text-xs"
|
className="m-0 text-xs text-chalkboard-100 dark:text-energy-40"
|
||||||
data-testid="createdAt"
|
data-testid="createdAt"
|
||||||
>
|
>
|
||||||
Created{' '}
|
Created{' '}
|
||||||
@ -120,7 +121,7 @@ const ProjectSidebarMenu = ({
|
|||||||
) : (
|
) : (
|
||||||
<div className="flex-1 overflow-hidden" />
|
<div className="flex-1 overflow-hidden" />
|
||||||
)}
|
)}
|
||||||
<div className="p-4 flex flex-col gap-2 bg-energy-10/25 dark:bg-energy-110">
|
<div className="flex flex-col gap-2 p-4 bg-energy-10/25 dark:bg-energy-110">
|
||||||
<ExportButton
|
<ExportButton
|
||||||
className={{
|
className={{
|
||||||
button:
|
button:
|
||||||
|
|||||||
@ -20,14 +20,13 @@ import kclLanguage from 'editor/lsp/language'
|
|||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import { writeTextFile } from '@tauri-apps/api/fs'
|
import { writeTextFile } from '@tauri-apps/api/fs'
|
||||||
import { PROJECT_ENTRYPOINT } from 'lib/tauriFS'
|
|
||||||
import { toast } from 'react-hot-toast'
|
import { toast } from 'react-hot-toast'
|
||||||
import {
|
import {
|
||||||
EditorView,
|
EditorView,
|
||||||
addLineHighlight,
|
addLineHighlight,
|
||||||
lineHighlightField,
|
lineHighlightField,
|
||||||
} from 'editor/highlightextension'
|
} from 'editor/highlightextension'
|
||||||
import { isOverlap, roundOff } from 'lib/utils'
|
import { roundOff } from 'lib/utils'
|
||||||
import { kclErrToDiagnostic } from 'lang/errors'
|
import { kclErrToDiagnostic } from 'lang/errors'
|
||||||
import { CSSRuleObject } from 'tailwindcss/types/config'
|
import { CSSRuleObject } from 'tailwindcss/types/config'
|
||||||
import { useModelingContext } from 'hooks/useModelingContext'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
@ -112,7 +111,7 @@ export const TextEditor = ({
|
|||||||
}, [lspClient, isLSPServerReady])
|
}, [lspClient, isLSPServerReady])
|
||||||
|
|
||||||
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
||||||
const onChange = (newCode: string, viewUpdate: ViewUpdate) => {
|
const onChange = (newCode: string) => {
|
||||||
kclManager.setCodeAndExecute(newCode)
|
kclManager.setCodeAndExecute(newCode)
|
||||||
if (isTauri() && pathParams.id) {
|
if (isTauri() && pathParams.id) {
|
||||||
// Save the file to disk
|
// Save the file to disk
|
||||||
|
|||||||
63
src/components/WasmErrBanner.tsx
Normal file
63
src/components/WasmErrBanner.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { Dialog } from '@headlessui/react'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { ActionButton } from './ActionButton'
|
||||||
|
import { faX } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import { useKclContext } from 'lang/KclSinglton'
|
||||||
|
|
||||||
|
export function WasmErrBanner() {
|
||||||
|
const [isBannerDismissed, setBannerDismissed] = useState(false)
|
||||||
|
|
||||||
|
const { wasmInitFailed } = useKclContext()
|
||||||
|
|
||||||
|
if (!wasmInitFailed) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
className="fixed inset-0 top-auto z-50 bg-warn-20 text-warn-80 px-8 py-4"
|
||||||
|
open={!isBannerDismissed}
|
||||||
|
onClose={() => ({})}
|
||||||
|
>
|
||||||
|
<Dialog.Panel className="max-w-3xl mx-auto">
|
||||||
|
<div className="flex gap-2 justify-between items-start">
|
||||||
|
<h2 className="text-xl font-bold mb-4">
|
||||||
|
Problem with our WASM blob :(
|
||||||
|
</h2>
|
||||||
|
<ActionButton
|
||||||
|
Element="button"
|
||||||
|
onClick={() => setBannerDismissed(true)}
|
||||||
|
icon={{
|
||||||
|
icon: faX,
|
||||||
|
bgClassName:
|
||||||
|
'bg-warn-70 hover:bg-warn-80 dark:bg-warn-70 dark:hover:bg-warn-80',
|
||||||
|
iconClassName:
|
||||||
|
'text-warn-10 group-hover:text-warn-10 dark:text-warn-10 dark:group-hover:text-warn-10',
|
||||||
|
}}
|
||||||
|
className="!p-0 !bg-transparent !border-transparent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="https://webassembly.org/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
className="text-warn-80 dark:text-warn-80 dark:hover:text-warn-70 underline"
|
||||||
|
>
|
||||||
|
WASM or web assembly
|
||||||
|
</a>{' '}
|
||||||
|
is core part of how our app works. It might because you OS is not
|
||||||
|
up-to-date. If you're able to update your OS to a later version, try
|
||||||
|
that. If not create an issue on{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/KittyCAD/modeling-app"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
className="text-warn-80 dark:text-warn-80 dark:hover:text-warn-70 underline"
|
||||||
|
>
|
||||||
|
our Github
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</Dialog.Panel>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -7,6 +7,6 @@ export function useAbsoluteFilePath() {
|
|||||||
return (
|
return (
|
||||||
paths.FILE +
|
paths.FILE +
|
||||||
'/' +
|
'/' +
|
||||||
encodeURIComponent(routeData?.project?.path || BROWSER_FILE_NAME)
|
encodeURIComponent(routeData?.file?.path || BROWSER_FILE_NAME)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,7 @@ class KclManager {
|
|||||||
private _logs: string[] = []
|
private _logs: string[] = []
|
||||||
private _kclErrors: KCLError[] = []
|
private _kclErrors: KCLError[] = []
|
||||||
private _isExecuting = false
|
private _isExecuting = false
|
||||||
|
private _wasmInitFailed = true
|
||||||
|
|
||||||
engineCommandManager: EngineCommandManager
|
engineCommandManager: EngineCommandManager
|
||||||
private _defferer = deferExecution((code: string) => {
|
private _defferer = deferExecution((code: string) => {
|
||||||
@ -47,12 +48,14 @@ class KclManager {
|
|||||||
this.executeAst(ast)
|
this.executeAst(ast)
|
||||||
}, 600)
|
}, 600)
|
||||||
|
|
||||||
private _isExecutingCallback: (a: boolean) => void = () => {}
|
private _isExecutingCallback: (arg: boolean) => void = () => {}
|
||||||
private _codeCallBack: (arg: string) => void = () => {}
|
private _codeCallBack: (arg: string) => void = () => {}
|
||||||
private _astCallBack: (arg: Program) => void = () => {}
|
private _astCallBack: (arg: Program) => void = () => {}
|
||||||
private _programMemoryCallBack: (arg: ProgramMemory) => void = () => {}
|
private _programMemoryCallBack: (arg: ProgramMemory) => void = () => {}
|
||||||
private _logsCallBack: (arg: string[]) => void = () => {}
|
private _logsCallBack: (arg: string[]) => void = () => {}
|
||||||
private _kclErrorsCallBack: (arg: KCLError[]) => void = () => {}
|
private _kclErrorsCallBack: (arg: KCLError[]) => void = () => {}
|
||||||
|
private _wasmInitFailedCallback: (arg: boolean) => void = () => {}
|
||||||
|
private _executeCallback: () => void = () => {}
|
||||||
|
|
||||||
get ast() {
|
get ast() {
|
||||||
return this._ast
|
return this._ast
|
||||||
@ -106,6 +109,14 @@ class KclManager {
|
|||||||
this._isExecutingCallback(isExecuting)
|
this._isExecutingCallback(isExecuting)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get wasmInitFailed() {
|
||||||
|
return this._wasmInitFailed
|
||||||
|
}
|
||||||
|
set wasmInitFailed(wasmInitFailed) {
|
||||||
|
this._wasmInitFailed = wasmInitFailed
|
||||||
|
this._wasmInitFailedCallback(wasmInitFailed)
|
||||||
|
}
|
||||||
|
|
||||||
constructor(engineCommandManager: EngineCommandManager) {
|
constructor(engineCommandManager: EngineCommandManager) {
|
||||||
this.engineCommandManager = engineCommandManager
|
this.engineCommandManager = engineCommandManager
|
||||||
const storedCode = localStorage.getItem(PERSIST_CODE_TOKEN)
|
const storedCode = localStorage.getItem(PERSIST_CODE_TOKEN)
|
||||||
@ -131,6 +142,7 @@ class KclManager {
|
|||||||
setLogs,
|
setLogs,
|
||||||
setKclErrors,
|
setKclErrors,
|
||||||
setIsExecuting,
|
setIsExecuting,
|
||||||
|
setWasmInitFailed,
|
||||||
}: {
|
}: {
|
||||||
setCode: (arg: string) => void
|
setCode: (arg: string) => void
|
||||||
setProgramMemory: (arg: ProgramMemory) => void
|
setProgramMemory: (arg: ProgramMemory) => void
|
||||||
@ -138,6 +150,7 @@ class KclManager {
|
|||||||
setLogs: (arg: string[]) => void
|
setLogs: (arg: string[]) => void
|
||||||
setKclErrors: (arg: KCLError[]) => void
|
setKclErrors: (arg: KCLError[]) => void
|
||||||
setIsExecuting: (arg: boolean) => void
|
setIsExecuting: (arg: boolean) => void
|
||||||
|
setWasmInitFailed: (arg: boolean) => void
|
||||||
}) {
|
}) {
|
||||||
this._codeCallBack = setCode
|
this._codeCallBack = setCode
|
||||||
this._programMemoryCallBack = setProgramMemory
|
this._programMemoryCallBack = setProgramMemory
|
||||||
@ -145,11 +158,26 @@ class KclManager {
|
|||||||
this._logsCallBack = setLogs
|
this._logsCallBack = setLogs
|
||||||
this._kclErrorsCallBack = setKclErrors
|
this._kclErrorsCallBack = setKclErrors
|
||||||
this._isExecutingCallback = setIsExecuting
|
this._isExecutingCallback = setIsExecuting
|
||||||
|
this._wasmInitFailedCallback = setWasmInitFailed
|
||||||
|
}
|
||||||
|
registerExecuteCallback(callback: () => void) {
|
||||||
|
this._executeCallback = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
async ensureWasmInit() {
|
||||||
|
try {
|
||||||
|
await initPromise
|
||||||
|
if (this.wasmInitFailed) {
|
||||||
|
this.wasmInitFailed = false
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.wasmInitFailed = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeAst(ast: Program = this._ast, updateCode = false) {
|
async executeAst(ast: Program = this._ast, updateCode = false) {
|
||||||
|
await this.ensureWasmInit()
|
||||||
this.isExecuting = true
|
this.isExecuting = true
|
||||||
await initPromise
|
|
||||||
const { logs, errors, programMemory } = await executeAst({
|
const { logs, errors, programMemory } = await executeAst({
|
||||||
ast,
|
ast,
|
||||||
engineCommandManager: this.engineCommandManager,
|
engineCommandManager: this.engineCommandManager,
|
||||||
@ -164,9 +192,10 @@ class KclManager {
|
|||||||
this._code = recast(ast)
|
this._code = recast(ast)
|
||||||
this._codeCallBack(this._code)
|
this._codeCallBack(this._code)
|
||||||
}
|
}
|
||||||
|
this._executeCallback()
|
||||||
}
|
}
|
||||||
async executeAstMock(ast: Program = this._ast, updateCode = false) {
|
async executeAstMock(ast: Program = this._ast, updateCode = false) {
|
||||||
await initPromise
|
await this.ensureWasmInit()
|
||||||
const newCode = recast(ast)
|
const newCode = recast(ast)
|
||||||
const newAst = parse(newCode)
|
const newAst = parse(newCode)
|
||||||
await this?.engineCommandManager?.waitForReady
|
await this?.engineCommandManager?.waitForReady
|
||||||
@ -186,7 +215,7 @@ class KclManager {
|
|||||||
this._programMemory = programMemory
|
this._programMemory = programMemory
|
||||||
}
|
}
|
||||||
async executeCode(code?: string) {
|
async executeCode(code?: string) {
|
||||||
await initPromise
|
await this.ensureWasmInit()
|
||||||
await this?.engineCommandManager?.waitForReady
|
await this?.engineCommandManager?.waitForReady
|
||||||
if (!this?.engineCommandManager?.planesInitialized()) return
|
if (!this?.engineCommandManager?.planesInitialized()) return
|
||||||
const result = await executeCode({
|
const result = await executeCode({
|
||||||
@ -306,6 +335,7 @@ const KclContext = createContext({
|
|||||||
isExecuting: kclManager.isExecuting,
|
isExecuting: kclManager.isExecuting,
|
||||||
errors: kclManager.kclErrors,
|
errors: kclManager.kclErrors,
|
||||||
logs: kclManager.logs,
|
logs: kclManager.logs,
|
||||||
|
wasmInitFailed: kclManager.wasmInitFailed,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useKclContext() {
|
export function useKclContext() {
|
||||||
@ -326,6 +356,7 @@ export function KclContextProvider({
|
|||||||
const [isExecuting, setIsExecuting] = useState(false)
|
const [isExecuting, setIsExecuting] = useState(false)
|
||||||
const [errors, setErrors] = useState<KCLError[]>([])
|
const [errors, setErrors] = useState<KCLError[]>([])
|
||||||
const [logs, setLogs] = useState<string[]>([])
|
const [logs, setLogs] = useState<string[]>([])
|
||||||
|
const [wasmInitFailed, setWasmInitFailed] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
kclManager.registerCallBacks({
|
kclManager.registerCallBacks({
|
||||||
@ -335,6 +366,7 @@ export function KclContextProvider({
|
|||||||
setLogs,
|
setLogs,
|
||||||
setKclErrors: setErrors,
|
setKclErrors: setErrors,
|
||||||
setIsExecuting,
|
setIsExecuting,
|
||||||
|
setWasmInitFailed,
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
@ -346,6 +378,7 @@ export function KclContextProvider({
|
|||||||
isExecuting,
|
isExecuting,
|
||||||
errors,
|
errors,
|
||||||
logs,
|
logs,
|
||||||
|
wasmInitFailed,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -450,18 +450,18 @@ export class EngineConnection {
|
|||||||
videoTrackStats.forEach((videoTrackReport) => {
|
videoTrackStats.forEach((videoTrackReport) => {
|
||||||
if (videoTrackReport.type === 'inbound-rtp') {
|
if (videoTrackReport.type === 'inbound-rtp') {
|
||||||
client_metrics.rtc_frames_decoded =
|
client_metrics.rtc_frames_decoded =
|
||||||
videoTrackReport.framesDecoded
|
videoTrackReport.framesDecoded || 0
|
||||||
client_metrics.rtc_frames_dropped =
|
client_metrics.rtc_frames_dropped =
|
||||||
videoTrackReport.framesDropped
|
videoTrackReport.framesDropped || 0
|
||||||
client_metrics.rtc_frames_received =
|
client_metrics.rtc_frames_received =
|
||||||
videoTrackReport.framesReceived
|
videoTrackReport.framesReceived || 0
|
||||||
client_metrics.rtc_frames_per_second =
|
client_metrics.rtc_frames_per_second =
|
||||||
videoTrackReport.framesPerSecond || 0
|
videoTrackReport.framesPerSecond || 0
|
||||||
client_metrics.rtc_freeze_count =
|
client_metrics.rtc_freeze_count =
|
||||||
videoTrackReport.freezeCount || 0
|
videoTrackReport.freezeCount || 0
|
||||||
client_metrics.rtc_jitter_sec = videoTrackReport.jitter
|
client_metrics.rtc_jitter_sec = videoTrackReport.jitter || 0.0
|
||||||
client_metrics.rtc_keyframes_decoded =
|
client_metrics.rtc_keyframes_decoded =
|
||||||
videoTrackReport.keyFramesDecoded
|
videoTrackReport.keyFramesDecoded || 0
|
||||||
client_metrics.rtc_total_freezes_duration_sec =
|
client_metrics.rtc_total_freezes_duration_sec =
|
||||||
videoTrackReport.totalFreezesDuration || 0
|
videoTrackReport.totalFreezesDuration || 0
|
||||||
} else if (videoTrackReport.type === 'transport') {
|
} else if (videoTrackReport.type === 'transport') {
|
||||||
|
|||||||
@ -138,6 +138,7 @@ show(mySketch001)`
|
|||||||
node: ast,
|
node: ast,
|
||||||
programMemory,
|
programMemory,
|
||||||
to: [2, 3],
|
to: [2, 3],
|
||||||
|
from: [0, 0],
|
||||||
fnName: 'lineTo',
|
fnName: 'lineTo',
|
||||||
pathToNode: [
|
pathToNode: [
|
||||||
['body', ''],
|
['body', ''],
|
||||||
|
|||||||
@ -193,9 +193,6 @@ export const line: SketchLineHelper = {
|
|||||||
pathToNode,
|
pathToNode,
|
||||||
'VariableDeclarator'
|
'VariableDeclarator'
|
||||||
)
|
)
|
||||||
const variableName = varDec.id.name
|
|
||||||
const sketch = previousProgramMemory?.root?.[variableName]
|
|
||||||
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))
|
||||||
@ -969,7 +966,8 @@ export function addNewSketchLn({
|
|||||||
to,
|
to,
|
||||||
fnName,
|
fnName,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
}: Omit<CreateLineFnCallArgs, 'from'>): {
|
from,
|
||||||
|
}: CreateLineFnCallArgs): {
|
||||||
modifiedAst: Program
|
modifiedAst: Program
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
} {
|
} {
|
||||||
@ -984,12 +982,6 @@ export function addNewSketchLn({
|
|||||||
const { node: pipeExp, shallowPath: pipePath } = getNodeFromPath<
|
const { node: pipeExp, shallowPath: pipePath } = getNodeFromPath<
|
||||||
PipeExpression | CallExpression
|
PipeExpression | CallExpression
|
||||||
>(node, pathToNode, 'PipeExpression')
|
>(node, pathToNode, 'PipeExpression')
|
||||||
const variableName = varDec.id.name
|
|
||||||
const sketch = previousProgramMemory?.root?.[variableName]
|
|
||||||
if (sketch.type !== 'SketchGroup') throw new Error('not a SketchGroup')
|
|
||||||
|
|
||||||
const last = sketch.value[sketch.value.length - 1] || sketch.start
|
|
||||||
const from = last.to
|
|
||||||
return add({
|
return add({
|
||||||
node,
|
node,
|
||||||
previousProgramMemory,
|
previousProgramMemory,
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export interface PathReturn {
|
|||||||
|
|
||||||
export interface ModifyAstBase {
|
export interface ModifyAstBase {
|
||||||
node: Program
|
node: Program
|
||||||
|
// TODO #896: Remove ProgramMemory from this interface
|
||||||
previousProgramMemory: ProgramMemory
|
previousProgramMemory: ProgramMemory
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,13 +66,16 @@ const initialise = async () => {
|
|||||||
typeof window === 'undefined'
|
typeof window === 'undefined'
|
||||||
? 'http://127.0.0.1:3000'
|
? 'http://127.0.0.1:3000'
|
||||||
: window.location.origin.includes('tauri://localhost')
|
: window.location.origin.includes('tauri://localhost')
|
||||||
? 'tauri://localhost'
|
? 'tauri://localhost' // custom protocol for macOS
|
||||||
|
: window.location.origin.includes('tauri.localhost')
|
||||||
|
? 'https://tauri.localhost' // fallback for Windows
|
||||||
: window.location.origin.includes('localhost')
|
: window.location.origin.includes('localhost')
|
||||||
? 'http://localhost:3000'
|
? 'http://localhost:3000'
|
||||||
: window.location.origin && window.location.origin !== 'null'
|
: window.location.origin && window.location.origin !== 'null'
|
||||||
? window.location.origin
|
? window.location.origin
|
||||||
: 'http://localhost:3000'
|
: 'http://localhost:3000'
|
||||||
const fullUrl = baseUrl + '/wasm_lib_bg.wasm'
|
const fullUrl = baseUrl + '/wasm_lib_bg.wasm'
|
||||||
|
console.log(`Full URL for WASM: ${fullUrl}`)
|
||||||
const input = await fetch(fullUrl)
|
const input = await fetch(fullUrl)
|
||||||
const buffer = await input.arrayBuffer()
|
const buffer = await input.arrayBuffer()
|
||||||
return init(buffer)
|
return init(buffer)
|
||||||
|
|||||||
@ -5,10 +5,11 @@ import {
|
|||||||
readDir,
|
readDir,
|
||||||
writeTextFile,
|
writeTextFile,
|
||||||
} from '@tauri-apps/api/fs'
|
} from '@tauri-apps/api/fs'
|
||||||
import { documentDir, homeDir } from '@tauri-apps/api/path'
|
import { documentDir, homeDir, sep } from '@tauri-apps/api/path'
|
||||||
import { isTauri } from './isTauri'
|
import { isTauri } from './isTauri'
|
||||||
import { ProjectWithEntryPointMetadata } from '../Router'
|
import { ProjectWithEntryPointMetadata } from '../Router'
|
||||||
import { metadata } from 'tauri-plugin-fs-extra-api'
|
import { metadata } from 'tauri-plugin-fs-extra-api'
|
||||||
|
import { bracket } from './exampleKcl'
|
||||||
|
|
||||||
const PROJECT_FOLDER = 'kittycad-modeling-projects'
|
const PROJECT_FOLDER = 'kittycad-modeling-projects'
|
||||||
export const FILE_EXT = '.kcl'
|
export const FILE_EXT = '.kcl'
|
||||||
@ -70,7 +71,7 @@ export async function getProjectsInDir(projectDir: string) {
|
|||||||
|
|
||||||
const projectsWithMetadata = await Promise.all(
|
const projectsWithMetadata = await Promise.all(
|
||||||
readProjects.map(async (p) => ({
|
readProjects.map(async (p) => ({
|
||||||
entrypointMetadata: await metadata(p.path + '/' + PROJECT_ENTRYPOINT),
|
entrypointMetadata: await metadata(p.path + sep + PROJECT_ENTRYPOINT),
|
||||||
...p,
|
...p,
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
@ -224,7 +225,7 @@ export async function createNewProject(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await writeTextFile(path + '/' + PROJECT_ENTRYPOINT, '').catch((err) => {
|
await writeTextFile(path + sep + PROJECT_ENTRYPOINT, bracket).catch((err) => {
|
||||||
console.error('Error creating new file:', err)
|
console.error('Error creating new file:', err)
|
||||||
throw err
|
throw err
|
||||||
})
|
})
|
||||||
@ -232,13 +233,13 @@ export async function createNewProject(
|
|||||||
const m = await metadata(path)
|
const m = await metadata(path)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: path.slice(path.lastIndexOf('/') + 1),
|
name: path.slice(path.lastIndexOf(sep) + 1),
|
||||||
path: path,
|
path: path,
|
||||||
entrypointMetadata: m,
|
entrypointMetadata: m,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: PROJECT_ENTRYPOINT,
|
name: PROJECT_ENTRYPOINT,
|
||||||
path: path + '/' + PROJECT_ENTRYPOINT,
|
path: path + sep + PROJECT_ENTRYPOINT,
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -52,19 +52,20 @@
|
|||||||
"Update code selection cursors": "Complete line" | "Deselect all" | "Deselect axis" | "Deselect edge" | "Deselect face" | "Deselect point" | "Deselect segment" | "Select edge" | "Select face" | "Select point" | "Select segment";
|
"Update code selection cursors": "Complete line" | "Deselect all" | "Deselect axis" | "Deselect edge" | "Deselect face" | "Deselect point" | "Deselect segment" | "Select edge" | "Select face" | "Select point" | "Select segment";
|
||||||
"create path": "Select default plane";
|
"create path": "Select default plane";
|
||||||
"default_camera_disable_sketch_mode": "Cancel";
|
"default_camera_disable_sketch_mode": "Cancel";
|
||||||
"edit mode enter": "Enter sketch";
|
"edit mode enter": "Enter sketch" | "Re-execute";
|
||||||
"edit_mode_exit": "Cancel";
|
"edit_mode_exit": "Cancel";
|
||||||
"equip select": "CancelSketch" | "Constrain equal length" | "Constrain horizontally align" | "Constrain parallel" | "Constrain remove constraints" | "Constrain vertically align" | "Deselect point" | "Deselect segment" | "Enter sketch" | "Make segment horizontal" | "Make segment vertical" | "Select default plane" | "Select point" | "Select segment" | "Set selection" | "done.invoke.get-angle-info" | "done.invoke.get-horizontal-info" | "done.invoke.get-length-info" | "done.invoke.get-perpendicular-distance-info" | "done.invoke.get-vertical-info" | "error.platform.get-angle-info" | "error.platform.get-horizontal-info" | "error.platform.get-length-info" | "error.platform.get-perpendicular-distance-info" | "error.platform.get-vertical-info";
|
"equip select": "CancelSketch" | "Constrain equal length" | "Constrain horizontally align" | "Constrain parallel" | "Constrain remove constraints" | "Constrain vertically align" | "Deselect point" | "Deselect segment" | "Enter sketch" | "Make segment horizontal" | "Make segment vertical" | "Re-execute" | "Select default plane" | "Select point" | "Select segment" | "Set selection" | "done.invoke.get-angle-info" | "done.invoke.get-horizontal-info" | "done.invoke.get-length-info" | "done.invoke.get-perpendicular-distance-info" | "done.invoke.get-vertical-info" | "error.platform.get-angle-info" | "error.platform.get-horizontal-info" | "error.platform.get-length-info" | "error.platform.get-perpendicular-distance-info" | "error.platform.get-vertical-info";
|
||||||
"hide default planes": "Cancel" | "Select default plane" | "xstate.stop";
|
"hide default planes": "Cancel" | "Select default plane" | "xstate.stop";
|
||||||
"reset sketch metadata": "Cancel" | "Select default plane";
|
"reset sketch metadata": "Cancel" | "Select default plane";
|
||||||
"set default plane id": "Select default plane";
|
"set default plane id": "Select default plane";
|
||||||
"set sketch metadata": "Enter sketch";
|
"set sketch metadata": "Enter sketch";
|
||||||
|
"set sketchMetadata from pathToNode": "Re-execute";
|
||||||
"set tool": "Equip new tool";
|
"set tool": "Equip new tool";
|
||||||
"set tool line": "Equip tool";
|
"set tool line": "Equip tool";
|
||||||
"set tool move": "Equip move tool" | "Set selection";
|
"set tool move": "Equip move tool" | "Re-execute" | "Set selection";
|
||||||
"show default planes": "Enter sketch";
|
"show default planes": "Enter sketch";
|
||||||
"sketch exit execute": "Cancel" | "Complete line" | "xstate.stop";
|
"sketch exit execute": "Cancel" | "Complete line" | "xstate.stop";
|
||||||
"sketch mode enabled": "Enter sketch" | "Select default plane";
|
"sketch mode enabled": "Enter sketch" | "Re-execute" | "Select default plane";
|
||||||
"toast extrude failed": "";
|
"toast extrude failed": "";
|
||||||
};
|
};
|
||||||
eventsCausingDelays: {
|
eventsCausingDelays: {
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import useStateMachineCommands from '../hooks/useStateMachineCommands'
|
|||||||
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { DEFAULT_PROJECT_NAME } from 'machines/settingsMachine'
|
import { DEFAULT_PROJECT_NAME } from 'machines/settingsMachine'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
// This route only opens in the Tauri desktop context for now,
|
// This route only opens in the Tauri desktop context for now,
|
||||||
// as defined in Router.tsx, so we can use the Tauri APIs and types.
|
// as defined in Router.tsx, so we can use the Tauri APIs and types.
|
||||||
@ -58,7 +59,7 @@ const Home = () => {
|
|||||||
setCommandBarOpen(false)
|
setCommandBarOpen(false)
|
||||||
navigate(
|
navigate(
|
||||||
`${paths.FILE}/${encodeURIComponent(
|
`${paths.FILE}/${encodeURIComponent(
|
||||||
context.defaultDirectory + '/' + event.data.name
|
context.defaultDirectory + sep + event.data.name
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -91,7 +92,7 @@ const Home = () => {
|
|||||||
name = interpolateProjectNameWithIndex(name, nextIndex)
|
name = interpolateProjectNameWithIndex(name, nextIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
await createNewProject(context.defaultDirectory + '/' + name)
|
await createNewProject(context.defaultDirectory + sep + name)
|
||||||
|
|
||||||
if (shouldUpdateDefaultProjectName) {
|
if (shouldUpdateDefaultProjectName) {
|
||||||
sendToSettings({
|
sendToSettings({
|
||||||
@ -114,8 +115,8 @@ const Home = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await renameFile(
|
await renameFile(
|
||||||
context.defaultDirectory + '/' + oldName,
|
context.defaultDirectory + sep + oldName,
|
||||||
context.defaultDirectory + '/' + name
|
context.defaultDirectory + sep + name
|
||||||
)
|
)
|
||||||
return `Successfully renamed "${oldName}" to "${name}"`
|
return `Successfully renamed "${oldName}" to "${name}"`
|
||||||
},
|
},
|
||||||
@ -123,7 +124,7 @@ const Home = () => {
|
|||||||
context: ContextFrom<typeof homeMachine>,
|
context: ContextFrom<typeof homeMachine>,
|
||||||
event: EventFrom<typeof homeMachine, 'Delete project'>
|
event: EventFrom<typeof homeMachine, 'Delete project'>
|
||||||
) => {
|
) => {
|
||||||
await removeDir(context.defaultDirectory + '/' + event.data.name, {
|
await removeDir(context.defaultDirectory + sep + event.data.name, {
|
||||||
recursive: true,
|
recursive: true,
|
||||||
})
|
})
|
||||||
return `Successfully deleted "${event.data.name}"`
|
return `Successfully deleted "${event.data.name}"`
|
||||||
@ -172,9 +173,9 @@ const Home = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen overflow-hidden relative flex flex-col">
|
<div className="relative flex flex-col h-screen overflow-hidden">
|
||||||
<AppHeader showToolbar={false} />
|
<AppHeader showToolbar={false} />
|
||||||
<div className="my-24 px-4 lg:px-0 overflow-y-auto max-w-5xl w-full mx-auto">
|
<div className="w-full max-w-5xl px-4 mx-auto my-24 overflow-y-auto lg:px-0">
|
||||||
<section className="flex justify-between">
|
<section className="flex justify-between">
|
||||||
<h1 className="text-3xl text-bold">Your Projects</h1>
|
<h1 className="text-3xl text-bold">Your Projects</h1>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
@ -235,7 +236,7 @@ const Home = () => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{projects.length > 0 ? (
|
{projects.length > 0 ? (
|
||||||
<ul className="my-8 w-full grid grid-cols-4 gap-4">
|
<ul className="grid w-full grid-cols-4 gap-4 my-8">
|
||||||
{projects.sort(getSortFunction(sort)).map((project) => (
|
{projects.sort(getSortFunction(sort)).map((project) => (
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
key={project.name}
|
key={project.name}
|
||||||
@ -246,7 +247,7 @@ const Home = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p className="rounded my-8 border border-dashed border-chalkboard-30 dark:border-chalkboard-70 p-4">
|
<p className="p-4 my-8 border border-dashed rounded border-chalkboard-30 dark:border-chalkboard-70">
|
||||||
No Projects found, ready to make your first one?
|
No Projects found, ready to make your first one?
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -24,8 +24,15 @@ export default function Export() {
|
|||||||
Try opening the project menu and clicking "Export Model".
|
Try opening the project menu and clicking "Export Model".
|
||||||
</p>
|
</p>
|
||||||
<p className="my-4">
|
<p className="my-4">
|
||||||
KittyCAD Modeling App uses our open-source extension proposal for
|
KittyCAD Modeling App uses{' '}
|
||||||
the GLTF file format.{' '}
|
<a
|
||||||
|
href="https://kittycad.io/gltf-format-extension"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
our open-source extension proposal
|
||||||
|
</a>{' '}
|
||||||
|
for the GLTF file format.{' '}
|
||||||
<a
|
<a
|
||||||
href="https://kittycad.io/docs/api/convert-cad-file"
|
href="https://kittycad.io/docs/api/convert-cad-file"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
|
|||||||
@ -4,13 +4,23 @@ import { useDismiss } from '.'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { bracket } from 'lib/exampleKcl'
|
import { bracket } from 'lib/exampleKcl'
|
||||||
import { kclManager } from 'lang/KclSinglton'
|
import { kclManager } from 'lang/KclSinglton'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function FutureWork() {
|
export default function FutureWork() {
|
||||||
|
const { send } = useModelingContext()
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
kclManager.setCode(bracket)
|
if (kclManager.engineCommandManager.engineConnection?.isReady()) {
|
||||||
}, [kclManager.setCode])
|
// If the engine is ready, promptly execute the loaded code
|
||||||
|
kclManager.setCodeAndExecute(bracket)
|
||||||
|
} else {
|
||||||
|
// Otherwise, just set the code and wait for the connection to complete
|
||||||
|
kclManager.setCode(bracket)
|
||||||
|
}
|
||||||
|
|
||||||
|
send({ type: 'Cancel' }) // in case the user hit 'Next' while still in sketch mode
|
||||||
|
}, [send])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-center inset-0 bg-chalkboard-100/50 z-50">
|
<div className="fixed grid justify-center items-center inset-0 bg-chalkboard-100/50 z-50">
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
|||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
import { bracket } from 'lib/exampleKcl'
|
import { bracket } from 'lib/exampleKcl'
|
||||||
import {
|
import {
|
||||||
|
PROJECT_ENTRYPOINT,
|
||||||
createNewProject,
|
createNewProject,
|
||||||
getNextProjectIndex,
|
getNextProjectIndex,
|
||||||
getProjectsInDir,
|
getProjectsInDir,
|
||||||
@ -20,6 +21,7 @@ import { useNavigate } from 'react-router-dom'
|
|||||||
import { paths } from 'Router'
|
import { paths } from 'Router'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { kclManager } from 'lang/KclSinglton'
|
import { kclManager } from 'lang/KclSinglton'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
function OnboardingWithNewFile() {
|
function OnboardingWithNewFile() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@ -41,12 +43,16 @@ function OnboardingWithNewFile() {
|
|||||||
ONBOARDING_PROJECT_NAME,
|
ONBOARDING_PROJECT_NAME,
|
||||||
nextIndex
|
nextIndex
|
||||||
)
|
)
|
||||||
const newFile = await createNewProject(defaultDirectory + '/' + name)
|
const newFile = await createNewProject(defaultDirectory + sep + name)
|
||||||
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
|
navigate(
|
||||||
|
`${paths.FILE}/${encodeURIComponent(
|
||||||
|
newFile.path + sep + PROJECT_ENTRYPOINT
|
||||||
|
)}${paths.ONBOARDING.INDEX}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed inset-0 z-50 grid place-content-center bg-chalkboard-110/50">
|
||||||
<div className="max-w-3xl bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
<div className="max-w-3xl p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
||||||
{!isTauri() ? (
|
{!isTauri() ? (
|
||||||
<>
|
<>
|
||||||
<h1 className="text-2xl font-bold text-warn-80 dark:text-warn-10">
|
<h1 className="text-2xl font-bold text-warn-80 dark:text-warn-10">
|
||||||
@ -84,7 +90,7 @@ function OnboardingWithNewFile() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<h1 className="text-2xl font-bold flex gap-4 flex-wrap items-center">
|
<h1 className="flex flex-wrap items-center gap-4 text-2xl font-bold">
|
||||||
Would you like to create a new project?
|
Would you like to create a new project?
|
||||||
</h1>
|
</h1>
|
||||||
<section className="my-12">
|
<section className="my-12">
|
||||||
@ -110,7 +116,11 @@ function OnboardingWithNewFile() {
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={createAndOpenNewProject}
|
onClick={() => {
|
||||||
|
createAndOpenNewProject()
|
||||||
|
kclManager.setCode(bracket)
|
||||||
|
dismiss()
|
||||||
|
}}
|
||||||
icon={{ icon: faArrowRight }}
|
icon={{ icon: faArrowRight }}
|
||||||
>
|
>
|
||||||
Make a new project
|
Make a new project
|
||||||
@ -138,21 +148,22 @@ export default function Introduction() {
|
|||||||
: ''
|
: ''
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.CAMERA)
|
const next = useNextClick(onboardingPaths.CAMERA)
|
||||||
|
const isStarterCode = kclManager.code === '' || kclManager.code === bracket
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (kclManager.code === '') kclManager.setCode(bracket)
|
if (kclManager.code === '') kclManager.setCode(bracket)
|
||||||
}, [kclManager.code, kclManager.setCode])
|
}, [])
|
||||||
|
|
||||||
return !(kclManager.code !== '' && kclManager.code !== bracket) ? (
|
return isStarterCode ? (
|
||||||
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed inset-0 z-50 grid place-content-center bg-chalkboard-110/50">
|
||||||
<div className="max-w-3xl bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
<div className="max-w-3xl p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
||||||
<h1 className="text-2xl font-bold flex gap-4 flex-wrap items-center">
|
<h1 className="flex flex-wrap items-center gap-4 text-2xl font-bold">
|
||||||
<img
|
<img
|
||||||
src={`/kcma-logomark${getLogoTheme()}.svg`}
|
src={`/kcma-logomark${getLogoTheme()}.svg`}
|
||||||
alt="KittyCAD Modeling App"
|
alt="KittyCAD Modeling App"
|
||||||
className="max-w-full h-20"
|
className="h-20 max-w-full"
|
||||||
/>
|
/>
|
||||||
<span className="bg-energy-10 text-energy-80 px-3 py-1 rounded-full text-base">
|
<span className="px-3 py-1 text-base rounded-full bg-energy-10 text-energy-80">
|
||||||
Alpha
|
Alpha
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@ -11,7 +11,13 @@ export default function Sketching() {
|
|||||||
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
kclManager.setCode('')
|
if (kclManager.engineCommandManager.engineConnection?.isReady()) {
|
||||||
|
// If the engine is ready, promptly execute the loaded code
|
||||||
|
kclManager.setCodeAndExecute('')
|
||||||
|
} else {
|
||||||
|
// Otherwise, just set the code and wait for the connection to complete
|
||||||
|
kclManager.setCode('')
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import {
|
|||||||
interpolateProjectNameWithIndex,
|
interpolateProjectNameWithIndex,
|
||||||
} from 'lib/tauriFS'
|
} from 'lib/tauriFS'
|
||||||
import { ONBOARDING_PROJECT_NAME } from './Onboarding'
|
import { ONBOARDING_PROJECT_NAME } from './Onboarding'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
export const Settings = () => {
|
export const Settings = () => {
|
||||||
const loaderData =
|
const loaderData =
|
||||||
@ -95,7 +96,7 @@ export const Settings = () => {
|
|||||||
ONBOARDING_PROJECT_NAME,
|
ONBOARDING_PROJECT_NAME,
|
||||||
nextIndex
|
nextIndex
|
||||||
)
|
)
|
||||||
const newFile = await createNewProject(defaultDirectory + '/' + name)
|
const newFile = await createNewProject(defaultDirectory + sep + name)
|
||||||
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
|
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ export const Settings = () => {
|
|||||||
Close
|
Close
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</AppHeader>
|
</AppHeader>
|
||||||
<div className="max-w-5xl mx-auto my-24">
|
<div className="max-w-5xl mx-5 lg:mx-auto my-24">
|
||||||
<h1 className="text-4xl font-bold">User Settings</h1>
|
<h1 className="text-4xl font-bold">User Settings</h1>
|
||||||
<p className="max-w-2xl mt-6">
|
<p className="max-w-2xl mt-6">
|
||||||
Don't see the feature you want? Check to see if it's on{' '}
|
Don't see the feature you want? Check to see if it's on{' '}
|
||||||
|
|||||||
@ -2,12 +2,10 @@ import { create } from 'zustand'
|
|||||||
import { persist } from 'zustand/middleware'
|
import { persist } from 'zustand/middleware'
|
||||||
import { addLineHighlight, EditorView } from './editor/highlightextension'
|
import { addLineHighlight, EditorView } from './editor/highlightextension'
|
||||||
import { parse, Program, _executor, ProgramMemory } from './lang/wasm'
|
import { parse, Program, _executor, ProgramMemory } from './lang/wasm'
|
||||||
import { Selection, Selections, SelectionRangeTypeMap } from 'lib/selections'
|
import { Selection } from 'lib/selections'
|
||||||
import { enginelessExecutor } from './lib/testHelpers'
|
import { enginelessExecutor } from './lib/testHelpers'
|
||||||
import { EditorSelection } from '@codemirror/state'
|
|
||||||
import { EngineCommandManager } from './lang/std/engineConnection'
|
import { EngineCommandManager } from './lang/std/engineConnection'
|
||||||
import { KCLError } from './lang/errors'
|
import { KCLError } from './lang/errors'
|
||||||
import { kclManager } from 'lang/KclSinglton'
|
|
||||||
import { DefaultPlanes } from './wasm-lib/kcl/bindings/DefaultPlanes'
|
import { DefaultPlanes } from './wasm-lib/kcl/bindings/DefaultPlanes'
|
||||||
|
|
||||||
export type ToolTip =
|
export type ToolTip =
|
||||||
|
|||||||
477
src/wasm-lib/Cargo.lock
generated
477
src/wasm-lib/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -11,21 +11,21 @@ crate-type = ["cdylib"]
|
|||||||
bson = { version = "2.7.0", features = ["uuid-1", "chrono"] }
|
bson = { version = "2.7.0", features = ["uuid-1", "chrono"] }
|
||||||
gloo-utils = "0.2.0"
|
gloo-utils = "0.2.0"
|
||||||
kcl-lib = { path = "kcl" }
|
kcl-lib = { path = "kcl" }
|
||||||
kittycad = { version = "0.2.33", default-features = false, features = ["js"] }
|
kittycad = { workspace = true }
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.107"
|
||||||
uuid = { version = "1.4.1", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.5.0", features = ["v4", "js", "serde"] }
|
||||||
wasm-bindgen = "0.2.87"
|
wasm-bindgen = "0.2.87"
|
||||||
wasm-bindgen-futures = "0.4.37"
|
wasm-bindgen-futures = "0.4.37"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
image = "0.24.7"
|
image = "0.24.7"
|
||||||
kittycad = "0.2.33"
|
kittycad = { workspace = true, default-features = true }
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
reqwest = { version = "0.11.22", default-features = false }
|
reqwest = { version = "0.11.22", default-features = false }
|
||||||
tokio = { version = "1.33.0", features = ["rt-multi-thread", "macros", "time"] }
|
tokio = { version = "1.33.0", features = ["rt-multi-thread", "macros", "time"] }
|
||||||
twenty-twenty = "0.6.1"
|
twenty-twenty = "0.6.1"
|
||||||
uuid = { version = "1.4.1", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.5.0", features = ["v4", "js", "serde"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
@ -53,6 +53,9 @@ members = [
|
|||||||
"kcl",
|
"kcl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
kittycad = { version = "0.2.41", default-features = false, features = ["js"] }
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "executor"
|
name = "executor"
|
||||||
path = "tests/executor/main.rs"
|
path = "tests/executor/main.rs"
|
||||||
|
|||||||
@ -15,15 +15,15 @@ clap = { version = "4.4.6", features = ["cargo", "derive", "env", "unicode"], op
|
|||||||
dashmap = "5.5.3"
|
dashmap = "5.5.3"
|
||||||
derive-docs = { version = "0.1.4" }
|
derive-docs = { version = "0.1.4" }
|
||||||
#derive-docs = { path = "../derive-docs" }
|
#derive-docs = { path = "../derive-docs" }
|
||||||
kittycad = { version = "0.2.33", default-features = false, features = ["js"] }
|
kittycad = { workspace = true }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
parse-display = "0.8.2"
|
parse-display = "0.8.2"
|
||||||
schemars = { version = "0.8", features = ["impl_json_schema", "url", "uuid1"] }
|
schemars = { version = "0.8", features = ["impl_json_schema", "url", "uuid1"] }
|
||||||
serde = { version = "1.0.189", features = ["derive"] }
|
serde = { version = "1.0.189", features = ["derive"] }
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.107"
|
||||||
thiserror = "1.0.49"
|
thiserror = "1.0.50"
|
||||||
ts-rs = { version = "7", package = "ts-rs-json-value", features = ["serde-json-impl", "schemars-impl", "uuid-impl"] }
|
ts-rs = { version = "7", package = "ts-rs-json-value", features = ["serde-json-impl", "schemars-impl", "uuid-impl"] }
|
||||||
uuid = { version = "1.4.1", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.5.0", features = ["v4", "js", "serde"] }
|
||||||
winnow = "0.5.16"
|
winnow = "0.5.16"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
|||||||
@ -136,7 +136,7 @@ pub async fn modify_ast_for_sketch(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut additional_lines = Vec::new();
|
let mut additional_lines = Vec::new();
|
||||||
let mut last_point = first_control_points.points[1].clone();
|
let mut last_point = first_control_points.points[1];
|
||||||
for control_point in control_points[1..].iter() {
|
for control_point in control_points[1..].iter() {
|
||||||
additional_lines.push([
|
additional_lines.push([
|
||||||
(control_point.points[1].x - last_point.x),
|
(control_point.points[1].x - last_point.x),
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
//! Data types for the AST.
|
//! Data types for the AST.
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Write};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{Formatter, Write},
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use parse_display::{Display, FromStr};
|
use parse_display::{Display, FromStr};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Map;
|
use serde_json::{Map, Number as JNumber, Value as JValue};
|
||||||
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, Range as LspRange, SymbolKind};
|
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, DocumentSymbol, Range as LspRange, SymbolKind};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -371,13 +374,13 @@ impl BodyItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BodyItem> for crate::executor::SourceRange {
|
impl From<BodyItem> for SourceRange {
|
||||||
fn from(item: BodyItem) -> Self {
|
fn from(item: BodyItem) -> Self {
|
||||||
Self([item.start(), item.end()])
|
Self([item.start(), item.end()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&BodyItem> for crate::executor::SourceRange {
|
impl From<&BodyItem> for SourceRange {
|
||||||
fn from(item: &BodyItem) -> Self {
|
fn from(item: &BodyItem) -> Self {
|
||||||
Self([item.start(), item.end()])
|
Self([item.start(), item.end()])
|
||||||
}
|
}
|
||||||
@ -534,13 +537,13 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Value> for crate::executor::SourceRange {
|
impl From<Value> for SourceRange {
|
||||||
fn from(value: Value) -> Self {
|
fn from(value: Value) -> Self {
|
||||||
Self([value.start(), value.end()])
|
Self([value.start(), value.end()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Value> for crate::executor::SourceRange {
|
impl From<&Value> for SourceRange {
|
||||||
fn from(value: &Value) -> Self {
|
fn from(value: &Value) -> Self {
|
||||||
Self([value.start(), value.end()])
|
Self([value.start(), value.end()])
|
||||||
}
|
}
|
||||||
@ -558,13 +561,13 @@ pub enum BinaryPart {
|
|||||||
MemberExpression(Box<MemberExpression>),
|
MemberExpression(Box<MemberExpression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BinaryPart> for crate::executor::SourceRange {
|
impl From<BinaryPart> for SourceRange {
|
||||||
fn from(value: BinaryPart) -> Self {
|
fn from(value: BinaryPart) -> Self {
|
||||||
Self([value.start(), value.end()])
|
Self([value.start(), value.end()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&BinaryPart> for crate::executor::SourceRange {
|
impl From<&BinaryPart> for SourceRange {
|
||||||
fn from(value: &BinaryPart) -> Self {
|
fn from(value: &BinaryPart) -> Self {
|
||||||
Self([value.start(), value.end()])
|
Self([value.start(), value.end()])
|
||||||
}
|
}
|
||||||
@ -640,7 +643,7 @@ impl BinaryPart {
|
|||||||
pipe_info: &mut PipeInfo,
|
pipe_info: &mut PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
|
// We DO NOT set this globally because if we did and this was called inside a pipe it would
|
||||||
// stop the execution of the pipe.
|
// stop the execution of the pipe.
|
||||||
// THIS IS IMPORTANT.
|
// THIS IS IMPORTANT.
|
||||||
let mut new_pipe_info = pipe_info.clone();
|
let mut new_pipe_info = pipe_info.clone();
|
||||||
@ -930,7 +933,7 @@ impl CallExpression {
|
|||||||
binary_expression.get_result(memory, pipe_info, ctx).await?
|
binary_expression.get_result(memory, pipe_info, ctx).await?
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => {
|
Value::CallExpression(call_expression) => {
|
||||||
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
|
// We DO NOT set this globally because if we did and this was called inside a pipe it would
|
||||||
// stop the execution of the pipe.
|
// stop the execution of the pipe.
|
||||||
// THIS IS IMPORTANT.
|
// THIS IS IMPORTANT.
|
||||||
let mut new_pipe_info = pipe_info.clone();
|
let mut new_pipe_info = pipe_info.clone();
|
||||||
@ -1312,10 +1315,70 @@ impl VariableDeclarator {
|
|||||||
pub struct Literal {
|
pub struct Literal {
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
pub value: serde_json::Value,
|
pub value: LiteralValue,
|
||||||
pub raw: String,
|
pub raw: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum LiteralValue {
|
||||||
|
// TODO: Use Cow<str> here so that static strings don't require alloc
|
||||||
|
String(String),
|
||||||
|
Number(JNumber),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for LiteralValue {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
JValue::from(self.to_owned()).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LiteralValue> for JValue {
|
||||||
|
fn from(value: LiteralValue) -> Self {
|
||||||
|
match value {
|
||||||
|
LiteralValue::String(x) => JValue::String(x),
|
||||||
|
LiteralValue::Number(x) => JValue::Number(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&'static str> for LiteralValue {
|
||||||
|
fn from(value: &'static str) -> Self {
|
||||||
|
Self::String(value.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<String> for LiteralValue {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self::String(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<JNumber> for LiteralValue {
|
||||||
|
fn from(value: JNumber) -> Self {
|
||||||
|
Self::Number(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u64> for LiteralValue {
|
||||||
|
fn from(value: u64) -> Self {
|
||||||
|
Self::Number(value.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i64> for LiteralValue {
|
||||||
|
fn from(value: i64) -> Self {
|
||||||
|
Self::Number(value.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for LiteralValue {
|
||||||
|
fn from(value: f64) -> Self {
|
||||||
|
JNumber::from_f64(value)
|
||||||
|
.map(Self::Number)
|
||||||
|
.expect("Cannot use NaN or Inf here. TODO stop using json numbers here")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_value_meta!(Literal);
|
impl_value_meta!(Literal);
|
||||||
|
|
||||||
impl From<Literal> for Value {
|
impl From<Literal> for Value {
|
||||||
@ -1325,7 +1388,7 @@ impl From<Literal> for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Literal {
|
impl Literal {
|
||||||
pub fn new(value: serde_json::Value) -> Self {
|
pub fn new(value: LiteralValue) -> Self {
|
||||||
Self {
|
Self {
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
@ -1343,7 +1406,7 @@ impl Literal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn recast(&self) -> String {
|
fn recast(&self) -> String {
|
||||||
if let serde_json::Value::String(value) = &self.value {
|
if let JValue::String(value) = &self.value {
|
||||||
let quote = if self.raw.trim().starts_with('"') { '"' } else { '\'' };
|
let quote = if self.raw.trim().starts_with('"') { '"' } else { '\'' };
|
||||||
format!("{}{}{}", quote, value, quote)
|
format!("{}{}{}", quote, value, quote)
|
||||||
} else {
|
} else {
|
||||||
@ -1355,7 +1418,7 @@ impl Literal {
|
|||||||
impl From<Literal> for MemoryItem {
|
impl From<Literal> for MemoryItem {
|
||||||
fn from(literal: Literal) -> Self {
|
fn from(literal: Literal) -> Self {
|
||||||
MemoryItem::UserVal(UserVal {
|
MemoryItem::UserVal(UserVal {
|
||||||
value: literal.value.clone(),
|
value: literal.value.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: literal.into(),
|
source_range: literal.into(),
|
||||||
}],
|
}],
|
||||||
@ -1366,7 +1429,7 @@ impl From<Literal> for MemoryItem {
|
|||||||
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(UserVal {
|
MemoryItem::UserVal(UserVal {
|
||||||
value: literal.value.clone(),
|
value: literal.value.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: literal.into(),
|
source_range: literal.into(),
|
||||||
}],
|
}],
|
||||||
@ -1552,7 +1615,7 @@ impl ArrayExpression {
|
|||||||
binary_expression.get_result(memory, pipe_info, ctx).await?
|
binary_expression.get_result(memory, pipe_info, ctx).await?
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => {
|
Value::CallExpression(call_expression) => {
|
||||||
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
|
// We DO NOT set this globally because if we did and this was called inside a pipe it would
|
||||||
// stop the execution of the pipe.
|
// stop the execution of the pipe.
|
||||||
// THIS IS IMPORTANT.
|
// THIS IS IMPORTANT.
|
||||||
let mut new_pipe_info = pipe_info.clone();
|
let mut new_pipe_info = pipe_info.clone();
|
||||||
@ -1703,7 +1766,7 @@ impl ObjectExpression {
|
|||||||
binary_expression.get_result(memory, pipe_info, ctx).await?
|
binary_expression.get_result(memory, pipe_info, ctx).await?
|
||||||
}
|
}
|
||||||
Value::CallExpression(call_expression) => {
|
Value::CallExpression(call_expression) => {
|
||||||
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
|
// We DO NOT set this globally because if we did and this was called inside a pipe it would
|
||||||
// stop the execution of the pipe.
|
// stop the execution of the pipe.
|
||||||
// THIS IS IMPORTANT.
|
// THIS IS IMPORTANT.
|
||||||
let mut new_pipe_info = pipe_info.clone();
|
let mut new_pipe_info = pipe_info.clone();
|
||||||
@ -1831,13 +1894,13 @@ impl MemberObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MemberObject> for crate::executor::SourceRange {
|
impl From<MemberObject> for SourceRange {
|
||||||
fn from(obj: MemberObject) -> Self {
|
fn from(obj: MemberObject) -> Self {
|
||||||
Self([obj.start(), obj.end()])
|
Self([obj.start(), obj.end()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&MemberObject> for crate::executor::SourceRange {
|
impl From<&MemberObject> for SourceRange {
|
||||||
fn from(obj: &MemberObject) -> Self {
|
fn from(obj: &MemberObject) -> Self {
|
||||||
Self([obj.start(), obj.end()])
|
Self([obj.start(), obj.end()])
|
||||||
}
|
}
|
||||||
@ -1867,13 +1930,13 @@ impl LiteralIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LiteralIdentifier> for crate::executor::SourceRange {
|
impl From<LiteralIdentifier> for SourceRange {
|
||||||
fn from(id: LiteralIdentifier) -> Self {
|
fn from(id: LiteralIdentifier) -> Self {
|
||||||
Self([id.start(), id.end()])
|
Self([id.start(), id.end()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&LiteralIdentifier> for crate::executor::SourceRange {
|
impl From<&LiteralIdentifier> for SourceRange {
|
||||||
fn from(id: &LiteralIdentifier) -> Self {
|
fn from(id: &LiteralIdentifier) -> Self {
|
||||||
Self([id.start(), id.end()])
|
Self([id.start(), id.end()])
|
||||||
}
|
}
|
||||||
@ -1940,10 +2003,10 @@ impl MemberExpression {
|
|||||||
|
|
||||||
let array_json = array.get_json_value()?;
|
let array_json = array.get_json_value()?;
|
||||||
|
|
||||||
if let serde_json::Value::Array(array) = array_json {
|
if let JValue::Array(array) = array_json {
|
||||||
if let Some(value) = array.get(index) {
|
if let Some(value) = array.get(index) {
|
||||||
Ok(MemoryItem::UserVal(UserVal {
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
value: value.clone(),
|
value: value.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
}],
|
}],
|
||||||
@ -1966,11 +2029,11 @@ impl MemberExpression {
|
|||||||
let property_name = match &self.property {
|
let property_name = match &self.property {
|
||||||
LiteralIdentifier::Identifier(identifier) => identifier.name.to_string(),
|
LiteralIdentifier::Identifier(identifier) => identifier.name.to_string(),
|
||||||
LiteralIdentifier::Literal(literal) => {
|
LiteralIdentifier::Literal(literal) => {
|
||||||
let value = literal.value.clone();
|
let value = literal.value.into();
|
||||||
// Parse this as a string.
|
// Parse this as a string.
|
||||||
if let serde_json::Value::String(string) = value {
|
if let JValue::String(string) = value {
|
||||||
string
|
string
|
||||||
} else if let serde_json::Value::Number(_) = &value {
|
} else if let JValue::Number(_) = &value {
|
||||||
// It can also be a number if we are getting a member of an array.
|
// It can also be a number if we are getting a member of an array.
|
||||||
return self.get_result_array(memory, parse_json_number_as_usize(&value, self.into())?);
|
return self.get_result_array(memory, parse_json_number_as_usize(&value, self.into())?);
|
||||||
} else {
|
} else {
|
||||||
@ -1992,10 +2055,10 @@ impl MemberExpression {
|
|||||||
|
|
||||||
let object_json = object.get_json_value()?;
|
let object_json = object.get_json_value()?;
|
||||||
|
|
||||||
if let serde_json::Value::Object(map) = object_json {
|
if let JValue::Object(map) = object_json {
|
||||||
if let Some(value) = map.get(&property_name) {
|
if let Some(value) = map.get(&property_name) {
|
||||||
Ok(MemoryItem::UserVal(UserVal {
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
value: value.clone(),
|
value: value.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
}],
|
}],
|
||||||
@ -2133,7 +2196,7 @@ impl BinaryExpression {
|
|||||||
pipe_info: &mut PipeInfo,
|
pipe_info: &mut PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
|
// We DO NOT set this globally because if we did and this was called inside a pipe it would
|
||||||
// stop the execution of the pipe.
|
// stop the execution of the pipe.
|
||||||
// THIS IS IMPORTANT.
|
// THIS IS IMPORTANT.
|
||||||
let mut new_pipe_info = pipe_info.clone();
|
let mut new_pipe_info = pipe_info.clone();
|
||||||
@ -2156,7 +2219,7 @@ impl BinaryExpression {
|
|||||||
parse_json_value_as_string(&left_json_value),
|
parse_json_value_as_string(&left_json_value),
|
||||||
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 = JValue::String(format!("{}{}", left, right)).into();
|
||||||
return Ok(MemoryItem::UserVal(UserVal {
|
return Ok(MemoryItem::UserVal(UserVal {
|
||||||
value,
|
value,
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
@ -2169,7 +2232,7 @@ impl BinaryExpression {
|
|||||||
let left = parse_json_number_as_f64(&left_json_value, self.left.clone().into())?;
|
let left = parse_json_number_as_f64(&left_json_value, self.left.clone().into())?;
|
||||||
let right = parse_json_number_as_f64(&right_json_value, self.right.clone().into())?;
|
let right = parse_json_number_as_f64(&right_json_value, self.right.clone().into())?;
|
||||||
|
|
||||||
let value: serde_json::Value = match self.operator {
|
let value: JNumber = match self.operator {
|
||||||
BinaryOperator::Add => (left + right).into(),
|
BinaryOperator::Add => (left + right).into(),
|
||||||
BinaryOperator::Sub => (left - right).into(),
|
BinaryOperator::Sub => (left - right).into(),
|
||||||
BinaryOperator::Mul => (left * right).into(),
|
BinaryOperator::Mul => (left * right).into(),
|
||||||
@ -2178,7 +2241,7 @@ impl BinaryExpression {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(MemoryItem::UserVal(UserVal {
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
value,
|
value: value.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
}],
|
}],
|
||||||
@ -2192,8 +2255,8 @@ impl BinaryExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_json_number_as_f64(j: &serde_json::Value, source_range: SourceRange) -> Result<f64, KclError> {
|
pub fn parse_json_number_as_f64(j: &JValue, source_range: SourceRange) -> Result<f64, KclError> {
|
||||||
if let serde_json::Value::Number(n) = &j {
|
if let JValue::Number(n) = &j {
|
||||||
n.as_f64().ok_or_else(|| {
|
n.as_f64().ok_or_else(|| {
|
||||||
KclError::Syntax(KclErrorDetails {
|
KclError::Syntax(KclErrorDetails {
|
||||||
source_ranges: vec![source_range],
|
source_ranges: vec![source_range],
|
||||||
@ -2208,8 +2271,8 @@ pub fn parse_json_number_as_f64(j: &serde_json::Value, source_range: SourceRange
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_json_number_as_usize(j: &serde_json::Value, source_range: SourceRange) -> Result<usize, KclError> {
|
pub fn parse_json_number_as_usize(j: &JValue, source_range: SourceRange) -> Result<usize, KclError> {
|
||||||
if let serde_json::Value::Number(n) = &j {
|
if let JValue::Number(n) = &j {
|
||||||
Ok(n.as_i64().ok_or_else(|| {
|
Ok(n.as_i64().ok_or_else(|| {
|
||||||
KclError::Syntax(KclErrorDetails {
|
KclError::Syntax(KclErrorDetails {
|
||||||
source_ranges: vec![source_range],
|
source_ranges: vec![source_range],
|
||||||
@ -2224,8 +2287,8 @@ pub fn parse_json_number_as_usize(j: &serde_json::Value, source_range: SourceRan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_json_value_as_string(j: &serde_json::Value) -> Option<String> {
|
pub fn parse_json_value_as_string(j: &JValue) -> Option<String> {
|
||||||
if let serde_json::Value::String(n) = &j {
|
if let JValue::String(n) = &j {
|
||||||
Some(n.clone())
|
Some(n.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -2307,7 +2370,7 @@ impl UnaryExpression {
|
|||||||
pipe_info: &mut PipeInfo,
|
pipe_info: &mut PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
// We DO NOT set this gloablly because if we did and this was called inside a pipe it would
|
// We DO NOT set this globally because if we did and this was called inside a pipe it would
|
||||||
// stop the execution of the pipe.
|
// stop the execution of the pipe.
|
||||||
// THIS IS IMPORTANT.
|
// THIS IS IMPORTANT.
|
||||||
let mut new_pipe_info = pipe_info.clone();
|
let mut new_pipe_info = pipe_info.clone();
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
|
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{BodyItem, Function, FunctionExpression, Value},
|
ast::types::{BodyItem, Function, FunctionExpression, LiteralValue, Value},
|
||||||
engine::{EngineConnection, EngineManager},
|
engine::{EngineConnection, EngineManager},
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
};
|
};
|
||||||
@ -183,7 +183,7 @@ impl DefaultPlanes {
|
|||||||
SourceRange::default(),
|
SourceRange::default(),
|
||||||
ModelingCmd::MakePlane {
|
ModelingCmd::MakePlane {
|
||||||
clobber: false,
|
clobber: false,
|
||||||
origin: default_origin.clone(),
|
origin: default_origin,
|
||||||
size: default_size,
|
size: default_size,
|
||||||
x_axis: Point3D { x: 1.0, y: 0.0, z: 0.0 },
|
x_axis: Point3D { x: 1.0, y: 0.0, z: 0.0 },
|
||||||
y_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 },
|
y_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 },
|
||||||
@ -216,7 +216,7 @@ impl DefaultPlanes {
|
|||||||
SourceRange::default(),
|
SourceRange::default(),
|
||||||
ModelingCmd::MakePlane {
|
ModelingCmd::MakePlane {
|
||||||
clobber: false,
|
clobber: false,
|
||||||
origin: default_origin.clone(),
|
origin: default_origin,
|
||||||
size: default_size,
|
size: default_size,
|
||||||
x_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 },
|
x_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 },
|
||||||
y_axis: Point3D { x: 0.0, y: 0.0, z: 1.0 },
|
y_axis: Point3D { x: 0.0, y: 0.0, z: 1.0 },
|
||||||
@ -282,7 +282,7 @@ impl DefaultPlanes {
|
|||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
#[serde(tag = "type", rename_all = "camelCase")]
|
#[serde(tag = "type", rename_all = "camelCase")]
|
||||||
pub struct UserVal {
|
pub struct UserVal {
|
||||||
pub value: serde_json::Value,
|
pub value: LiteralValue,
|
||||||
#[serde(rename = "__meta")]
|
#[serde(rename = "__meta")]
|
||||||
pub meta: Vec<Metadata>,
|
pub meta: Vec<Metadata>,
|
||||||
}
|
}
|
||||||
@ -336,7 +336,7 @@ 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(user_val) = self {
|
if let MemoryItem::UserVal(user_val) = self {
|
||||||
Ok(user_val.value.clone())
|
Ok(user_val.value.into())
|
||||||
} else {
|
} else {
|
||||||
serde_json::to_value(self).map_err(|err| {
|
serde_json::to_value(self).map_err(|err| {
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
|
|||||||
@ -575,7 +575,7 @@ impl ReversePolishNotation {
|
|||||||
),
|
),
|
||||||
MathExpression::ExtendedLiteral(lit) => (
|
MathExpression::ExtendedLiteral(lit) => (
|
||||||
BinaryPart::Literal(Box::new(Literal {
|
BinaryPart::Literal(Box::new(Literal {
|
||||||
value: lit.value.clone(),
|
value: lit.value.into(),
|
||||||
start: lit.start,
|
start: lit.start,
|
||||||
end: lit.end,
|
end: lit.end,
|
||||||
raw: lit.raw.clone(),
|
raw: lit.raw.clone(),
|
||||||
@ -613,7 +613,7 @@ impl ReversePolishNotation {
|
|||||||
),
|
),
|
||||||
MathExpression::ExtendedLiteral(lit) => (
|
MathExpression::ExtendedLiteral(lit) => (
|
||||||
BinaryPart::Literal(Box::new(Literal {
|
BinaryPart::Literal(Box::new(Literal {
|
||||||
value: lit.value.clone(),
|
value: lit.value.into(),
|
||||||
start: lit.start,
|
start: lit.start,
|
||||||
end: lit.end,
|
end: lit.end,
|
||||||
raw: lit.raw.clone(),
|
raw: lit.raw.clone(),
|
||||||
@ -714,13 +714,13 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 5,
|
end: 5,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 4,
|
start: 4,
|
||||||
end: 5,
|
end: 5,
|
||||||
@ -741,13 +741,13 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 3,
|
end: 3,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 2,
|
start: 2,
|
||||||
end: 3,
|
end: 3,
|
||||||
@ -768,13 +768,13 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 4,
|
end: 4,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 3,
|
start: 3,
|
||||||
end: 4,
|
end: 4,
|
||||||
@ -795,7 +795,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 9,
|
end: 9,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -805,13 +805,13 @@ mod test {
|
|||||||
start: 4,
|
start: 4,
|
||||||
end: 9,
|
end: 9,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 4,
|
start: 4,
|
||||||
end: 5,
|
end: 5,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 8,
|
start: 8,
|
||||||
end: 9,
|
end: 9,
|
||||||
@ -833,7 +833,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 13,
|
end: 13,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -843,13 +843,13 @@ mod test {
|
|||||||
start: 6,
|
start: 6,
|
||||||
end: 11,
|
end: 11,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 6,
|
start: 6,
|
||||||
end: 7,
|
end: 7,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 10,
|
start: 10,
|
||||||
end: 11,
|
end: 11,
|
||||||
@ -875,7 +875,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 13,
|
end: 13,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -885,13 +885,13 @@ mod test {
|
|||||||
start: 6,
|
start: 6,
|
||||||
end: 11,
|
end: 11,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 6,
|
start: 6,
|
||||||
end: 7,
|
end: 7,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 10,
|
start: 10,
|
||||||
end: 11,
|
end: 11,
|
||||||
@ -899,7 +899,7 @@ mod test {
|
|||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(4)),
|
value: 4.into(),
|
||||||
raw: "4".to_string(),
|
raw: "4".to_string(),
|
||||||
start: 16,
|
start: 16,
|
||||||
end: 17,
|
end: 17,
|
||||||
@ -920,7 +920,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 17,
|
end: 17,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -934,20 +934,20 @@ mod test {
|
|||||||
start: 6,
|
start: 6,
|
||||||
end: 11,
|
end: 11,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 6,
|
start: 6,
|
||||||
end: 7,
|
end: 7,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 10,
|
start: 10,
|
||||||
end: 11,
|
end: 11,
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(4)),
|
value: 4.into(),
|
||||||
raw: "4".to_string(),
|
raw: "4".to_string(),
|
||||||
start: 16,
|
start: 16,
|
||||||
end: 17,
|
end: 17,
|
||||||
@ -968,7 +968,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 24,
|
end: 24,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -986,27 +986,27 @@ mod test {
|
|||||||
start: 7,
|
start: 7,
|
||||||
end: 12,
|
end: 12,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 7,
|
start: 7,
|
||||||
end: 8,
|
end: 8,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 11,
|
start: 11,
|
||||||
end: 12,
|
end: 12,
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(4)),
|
value: 4.into(),
|
||||||
raw: "4".to_string(),
|
raw: "4".to_string(),
|
||||||
start: 17,
|
start: 17,
|
||||||
end: 18,
|
end: 18,
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(5)),
|
value: 5.into(),
|
||||||
raw: "5".to_string(),
|
raw: "5".to_string(),
|
||||||
start: 21,
|
start: 21,
|
||||||
end: 22,
|
end: 22,
|
||||||
@ -1027,7 +1027,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 17,
|
end: 17,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -1037,13 +1037,13 @@ mod test {
|
|||||||
start: 8,
|
start: 8,
|
||||||
end: 13,
|
end: 13,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 8,
|
start: 8,
|
||||||
end: 9,
|
end: 9,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 12,
|
start: 12,
|
||||||
end: 13,
|
end: 13,
|
||||||
@ -1189,13 +1189,13 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: code.find(")))").unwrap() + 3,
|
end: code.find(")))").unwrap() + 3,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 7,
|
start: 7,
|
||||||
end: 8,
|
end: 8,
|
||||||
@ -1243,7 +1243,7 @@ mod test {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 9,
|
end: 9,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(1)),
|
value: 1.into(),
|
||||||
raw: "1".to_string(),
|
raw: "1".to_string(),
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
@ -1253,13 +1253,13 @@ mod test {
|
|||||||
start: 4,
|
start: 4,
|
||||||
end: 9,
|
end: 9,
|
||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_string(),
|
raw: "2".to_string(),
|
||||||
start: 4,
|
start: 4,
|
||||||
end: 5,
|
end: 5,
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_string(),
|
raw: "3".to_string(),
|
||||||
start: 8,
|
start: 8,
|
||||||
end: 9,
|
end: 9,
|
||||||
|
|||||||
@ -246,7 +246,7 @@ impl Parser {
|
|||||||
Ok(Literal {
|
Ok(Literal {
|
||||||
start: token.start,
|
start: token.start,
|
||||||
end: token.end,
|
end: token.end,
|
||||||
value,
|
value: value.into(),
|
||||||
raw: token.value.clone(),
|
raw: token.value.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1833,7 +1833,7 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::types::BinaryOperator;
|
use crate::ast::types::{BinaryOperator, LiteralValue};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_make_identifier() {
|
fn test_make_identifier() {
|
||||||
@ -1986,7 +1986,7 @@ const key = 'c'"#,
|
|||||||
Literal {
|
Literal {
|
||||||
start: 4,
|
start: 4,
|
||||||
end: 5,
|
end: 5,
|
||||||
value: serde_json::Value::Number(5.into()),
|
value: LiteralValue::Number(5.into()),
|
||||||
raw: "5".to_string()
|
raw: "5".to_string()
|
||||||
},
|
},
|
||||||
literal
|
literal
|
||||||
@ -1996,7 +1996,7 @@ const key = 'c'"#,
|
|||||||
Literal {
|
Literal {
|
||||||
start: 7,
|
start: 7,
|
||||||
end: 14,
|
end: 14,
|
||||||
value: serde_json::Value::String("hello".to_string()),
|
value: "hello".into(),
|
||||||
raw: "\"hello\"".to_string()
|
raw: "\"hello\"".to_string()
|
||||||
},
|
},
|
||||||
literal
|
literal
|
||||||
@ -2014,13 +2014,13 @@ const key = 'c'"#,
|
|||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(5)),
|
value: 5.into(),
|
||||||
raw: "5".to_owned(),
|
raw: "5".to_owned(),
|
||||||
})),
|
})),
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
start: 4,
|
start: 4,
|
||||||
end: 7,
|
end: 7,
|
||||||
value: serde_json::Value::String("a".to_owned()),
|
value: "a".into(),
|
||||||
raw: r#""a""#.to_owned(),
|
raw: r#""a""#.to_owned(),
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
@ -2690,14 +2690,14 @@ show(mySk1)"#;
|
|||||||
left: BinaryPart::Literal(Box::new(Literal {
|
left: BinaryPart::Literal(Box::new(Literal {
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 1,
|
end: 1,
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(5)),
|
value: 5.into(),
|
||||||
raw: "5".to_string(),
|
raw: "5".to_string(),
|
||||||
})),
|
})),
|
||||||
operator: BinaryOperator::Add,
|
operator: BinaryOperator::Add,
|
||||||
right: BinaryPart::Literal(Box::new(Literal {
|
right: BinaryPart::Literal(Box::new(Literal {
|
||||||
start: 3,
|
start: 3,
|
||||||
end: 4,
|
end: 4,
|
||||||
value: serde_json::Value::Number(serde_json::Number::from(6)),
|
value: 6.into(),
|
||||||
raw: "6".to_string(),
|
raw: "6".to_string(),
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
|
|||||||
@ -10,10 +10,10 @@ use winnow::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{
|
ast::types::{
|
||||||
ArrayExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression, CommentStyle,
|
ArrayExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression, CommentStyle,
|
||||||
ExpressionStatement, FunctionExpression, Identifier, Literal, LiteralIdentifier, MemberExpression,
|
ExpressionStatement, FunctionExpression, Identifier, Literal, LiteralIdentifier, LiteralValue,
|
||||||
MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty, PipeExpression,
|
MemberExpression, MemberObject, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty,
|
||||||
PipeSubstitution, Program, ReturnStatement, UnaryExpression, UnaryOperator, Value, VariableDeclaration,
|
PipeExpression, PipeSubstitution, Program, ReturnStatement, UnaryExpression, UnaryOperator, Value,
|
||||||
VariableDeclarator, VariableKind,
|
VariableDeclaration, VariableDeclarator, VariableKind,
|
||||||
},
|
},
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::SourceRange,
|
executor::SourceRange,
|
||||||
@ -25,7 +25,7 @@ use crate::{
|
|||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
type PResult<O, E = error::ContextError> = winnow::prelude::PResult<O, E>;
|
type PResult<O, E = ContextError> = winnow::prelude::PResult<O, E>;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref STDLIB: StdLib = StdLib::new();
|
static ref STDLIB: StdLib = StdLib::new();
|
||||||
@ -216,7 +216,7 @@ pub fn string_literal(i: TokenSlice) -> PResult<Literal> {
|
|||||||
.try_map(|token: Token| match token.token_type {
|
.try_map(|token: Token| match token.token_type {
|
||||||
TokenType::String => {
|
TokenType::String => {
|
||||||
let s = token.value[1..token.value.len() - 1].to_string();
|
let s = token.value[1..token.value.len() - 1].to_string();
|
||||||
Ok((JValue::String(s), token))
|
Ok((LiteralValue::String(s), token))
|
||||||
}
|
}
|
||||||
_ => Err(KclError::Syntax(KclErrorDetails {
|
_ => Err(KclError::Syntax(KclErrorDetails {
|
||||||
source_ranges: token.as_source_ranges(),
|
source_ranges: token.as_source_ranges(),
|
||||||
@ -239,7 +239,7 @@ fn unsigned_number_literal(i: TokenSlice) -> PResult<Literal> {
|
|||||||
.try_map(|token: Token| match token.token_type {
|
.try_map(|token: Token| match token.token_type {
|
||||||
TokenType::Number => {
|
TokenType::Number => {
|
||||||
if let Ok(x) = token.value.parse::<i64>() {
|
if let Ok(x) = token.value.parse::<i64>() {
|
||||||
return Ok((JValue::Number(JNumber::from(x)), token));
|
return Ok((JNumber::from(x), token));
|
||||||
}
|
}
|
||||||
let x: f64 = token.value.parse().map_err(|_| {
|
let x: f64 = token.value.parse().map_err(|_| {
|
||||||
KclError::Syntax(KclErrorDetails {
|
KclError::Syntax(KclErrorDetails {
|
||||||
@ -249,7 +249,7 @@ fn unsigned_number_literal(i: TokenSlice) -> PResult<Literal> {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
match JNumber::from_f64(x) {
|
match JNumber::from_f64(x) {
|
||||||
Some(n) => Ok((JValue::Number(n), token)),
|
Some(n) => Ok((n, token)),
|
||||||
None => Err(KclError::Syntax(KclErrorDetails {
|
None => Err(KclError::Syntax(KclErrorDetails {
|
||||||
source_ranges: token.as_source_ranges(),
|
source_ranges: token.as_source_ranges(),
|
||||||
message: format!("Invalid float: {}", token.value),
|
message: format!("Invalid float: {}", token.value),
|
||||||
@ -266,7 +266,7 @@ fn unsigned_number_literal(i: TokenSlice) -> PResult<Literal> {
|
|||||||
Ok(Literal {
|
Ok(Literal {
|
||||||
start: token.start,
|
start: token.start,
|
||||||
end: token.end,
|
end: token.end,
|
||||||
value,
|
value: LiteralValue::Number(value),
|
||||||
raw: token.value.clone(),
|
raw: token.value.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ fn integer_range(i: TokenSlice) -> PResult<Vec<Value>> {
|
|||||||
Value::Literal(Box::new(Literal {
|
Value::Literal(Box::new(Literal {
|
||||||
start: token0.start,
|
start: token0.start,
|
||||||
end: token0.end,
|
end: token0.end,
|
||||||
value: JValue::Number(num.into()),
|
value: num.into(),
|
||||||
raw: num.to_string(),
|
raw: num.to_string(),
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
@ -1408,7 +1408,7 @@ const mySk1 = startSketchAt([0, 0])"#;
|
|||||||
let tokens = crate::token::lexer(r#"const x = y() |> /*hi*/ z(%)"#);
|
let tokens = crate::token::lexer(r#"const x = y() |> /*hi*/ z(%)"#);
|
||||||
let mut body = program.parse(&tokens).unwrap().body;
|
let mut body = program.parse(&tokens).unwrap().body;
|
||||||
let BodyItem::VariableDeclaration(mut item) = body.remove(0) else {
|
let BodyItem::VariableDeclaration(mut item) = body.remove(0) else {
|
||||||
panic!("expected vardec");
|
panic!("expected variable declaration");
|
||||||
};
|
};
|
||||||
let val = item.declarations.remove(0).init;
|
let val = item.declarations.remove(0).init;
|
||||||
let Value::PipeExpression(pipe) = val else {
|
let Value::PipeExpression(pipe) = val else {
|
||||||
@ -1461,7 +1461,7 @@ const mySk1 = startSketchAt([0, 0])"#;
|
|||||||
argument: Value::Literal(Box::new(Literal {
|
argument: Value::Literal(Box::new(Literal {
|
||||||
start: 32,
|
start: 32,
|
||||||
end: 33,
|
end: 33,
|
||||||
value: JValue::Number(JNumber::from(2)),
|
value: 2.into(),
|
||||||
raw: "2".to_owned(),
|
raw: "2".to_owned(),
|
||||||
})),
|
})),
|
||||||
})],
|
})],
|
||||||
@ -1616,7 +1616,7 @@ const mySk1 = startSketchAt([0, 0])"#;
|
|||||||
BinaryPart::Literal(Box::new(Literal {
|
BinaryPart::Literal(Box::new(Literal {
|
||||||
start: 9,
|
start: 9,
|
||||||
end: 10,
|
end: 10,
|
||||||
value: JValue::Number(JNumber::from(3)),
|
value: 3.into(),
|
||||||
raw: "3".to_owned(),
|
raw: "3".to_owned(),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|||||||
@ -4,10 +4,11 @@ use anyhow::Result;
|
|||||||
use derive_docs::stdlib;
|
use derive_docs::stdlib;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
|
||||||
|
use super::utils::between;
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{MemoryItem, SketchGroup},
|
executor::{MemoryItem, SketchGroup},
|
||||||
std::{utils::Angle, Args},
|
std::Args,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns the segment end of x.
|
/// Returns the segment end of x.
|
||||||
@ -174,7 +175,7 @@ fn inner_segment_angle(segment_name: &str, sketch_group: Box<SketchGroup>, args:
|
|||||||
})?;
|
})?;
|
||||||
let line = path.get_base();
|
let line = path.get_base();
|
||||||
|
|
||||||
let result = Angle::between(line.from.into(), line.to.into());
|
let result = between(line.from.into(), line.to.into());
|
||||||
|
|
||||||
Ok(result.degrees())
|
Ok(result.degrees())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use derive_docs::stdlib;
|
use derive_docs::stdlib;
|
||||||
use kittycad::types::{ModelingCmd, Point3D};
|
use kittycad::types::{Angle, ModelingCmd, Point3D};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::utils::Angle;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
@ -334,6 +333,16 @@ pub enum AngledLineData {
|
|||||||
AngleAndLength([f64; 2]),
|
AngleAndLength([f64; 2]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AngledLineData {
|
||||||
|
pub fn into_inner_line(self, to: [f64; 2]) -> LineData {
|
||||||
|
if let AngledLineData::AngleWithTag { tag, .. } = self {
|
||||||
|
LineData::PointWithTag { to, tag }
|
||||||
|
} else {
|
||||||
|
LineData::Point(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw an angled line.
|
/// Draw an angled line.
|
||||||
pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
let (data, sketch_group): (AngledLineData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||||
@ -429,16 +438,7 @@ async fn inner_angled_line_of_x_length(
|
|||||||
|
|
||||||
let to = get_y_component(Angle::from_degrees(angle), length);
|
let to = get_y_component(Angle::from_degrees(angle), length);
|
||||||
|
|
||||||
let new_sketch_group = inner_line(
|
let new_sketch_group = inner_line(data.into_inner_line(to.into()), sketch_group, args).await?;
|
||||||
if let AngledLineData::AngleWithTag { tag, .. } = data {
|
|
||||||
LineData::PointWithTag { to: to.into(), tag }
|
|
||||||
} else {
|
|
||||||
LineData::Point(to.into())
|
|
||||||
},
|
|
||||||
sketch_group,
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(new_sketch_group)
|
Ok(new_sketch_group)
|
||||||
}
|
}
|
||||||
@ -461,6 +461,16 @@ pub enum AngledLineToData {
|
|||||||
AngleAndPoint([f64; 2]),
|
AngleAndPoint([f64; 2]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AngledLineToData {
|
||||||
|
pub fn into_inner_line(self, x_to: f64, y_to: f64) -> LineToData {
|
||||||
|
if let AngledLineToData::AngleWithTag { tag, .. } = self {
|
||||||
|
LineToData::PointWithTag { to: [x_to, y_to], tag }
|
||||||
|
} else {
|
||||||
|
LineToData::Point([x_to, y_to])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw an angled line to a given x coordinate.
|
/// Draw an angled line to a given x coordinate.
|
||||||
pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, sketch_group): (AngledLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
let (data, sketch_group): (AngledLineToData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||||
@ -488,16 +498,7 @@ async fn inner_angled_line_to_x(
|
|||||||
let y_component = x_component * f64::tan(angle.to_radians());
|
let y_component = x_component * f64::tan(angle.to_radians());
|
||||||
let y_to = from.y + y_component;
|
let y_to = from.y + y_component;
|
||||||
|
|
||||||
let new_sketch_group = inner_line_to(
|
let new_sketch_group = inner_line_to(data.into_inner_line(x_to, y_to), sketch_group, args).await?;
|
||||||
if let AngledLineToData::AngleWithTag { tag, .. } = data {
|
|
||||||
LineToData::PointWithTag { to: [x_to, y_to], tag }
|
|
||||||
} else {
|
|
||||||
LineToData::Point([x_to, y_to])
|
|
||||||
},
|
|
||||||
sketch_group,
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(new_sketch_group)
|
Ok(new_sketch_group)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,16 +527,7 @@ async fn inner_angled_line_of_y_length(
|
|||||||
|
|
||||||
let to = get_x_component(Angle::from_degrees(angle), length);
|
let to = get_x_component(Angle::from_degrees(angle), length);
|
||||||
|
|
||||||
let new_sketch_group = inner_line(
|
let new_sketch_group = inner_line(data.into_inner_line(to.into()), sketch_group, args).await?;
|
||||||
if let AngledLineData::AngleWithTag { tag, .. } = data {
|
|
||||||
LineData::PointWithTag { to: to.into(), tag }
|
|
||||||
} else {
|
|
||||||
LineData::Point(to.into())
|
|
||||||
},
|
|
||||||
sketch_group,
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(new_sketch_group)
|
Ok(new_sketch_group)
|
||||||
}
|
}
|
||||||
@ -567,16 +559,7 @@ async fn inner_angled_line_to_y(
|
|||||||
let x_component = y_component / f64::tan(angle.to_radians());
|
let x_component = y_component / f64::tan(angle.to_radians());
|
||||||
let x_to = from.x + x_component;
|
let x_to = from.x + x_component;
|
||||||
|
|
||||||
let new_sketch_group = inner_line_to(
|
let new_sketch_group = inner_line_to(data.into_inner_line(x_to, y_to), sketch_group, args).await?;
|
||||||
if let AngledLineToData::AngleWithTag { tag, .. } = data {
|
|
||||||
LineToData::PointWithTag { to: [x_to, y_to], tag }
|
|
||||||
} else {
|
|
||||||
LineToData::Point([x_to, y_to])
|
|
||||||
},
|
|
||||||
sketch_group,
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(new_sketch_group)
|
Ok(new_sketch_group)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +568,7 @@ async fn inner_angled_line_to_y(
|
|||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
// TODO: make sure the docs on the args below are correct.
|
// TODO: make sure the docs on the args below are correct.
|
||||||
pub struct AngeledLineThatIntersectsData {
|
pub struct AngledLineThatIntersectsData {
|
||||||
/// The angle of the line.
|
/// The angle of the line.
|
||||||
pub angle: f64,
|
pub angle: f64,
|
||||||
/// The tag of the line to intersect with.
|
/// The tag of the line to intersect with.
|
||||||
@ -598,7 +581,7 @@ pub struct AngeledLineThatIntersectsData {
|
|||||||
|
|
||||||
/// Draw an angled line that intersects with a given line.
|
/// Draw an angled line that intersects with a given line.
|
||||||
pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, sketch_group): (AngeledLineThatIntersectsData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
let (data, sketch_group): (AngledLineThatIntersectsData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||||
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args).await?;
|
let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args).await?;
|
||||||
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
Ok(MemoryItem::SketchGroup(new_sketch_group))
|
||||||
}
|
}
|
||||||
@ -608,7 +591,7 @@ pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclEr
|
|||||||
name = "angledLineThatIntersects",
|
name = "angledLineThatIntersects",
|
||||||
}]
|
}]
|
||||||
async fn inner_angled_line_that_intersects(
|
async fn inner_angled_line_that_intersects(
|
||||||
data: AngeledLineThatIntersectsData,
|
data: AngledLineThatIntersectsData,
|
||||||
sketch_group: Box<SketchGroup>,
|
sketch_group: Box<SketchGroup>,
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> Result<Box<SketchGroup>, KclError> {
|
) -> Result<Box<SketchGroup>, KclError> {
|
||||||
@ -1049,6 +1032,8 @@ async fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: Args) ->
|
|||||||
segment: kittycad::types::PathSegment::Arc {
|
segment: kittycad::types::PathSegment::Arc {
|
||||||
angle_start: angle_start.degrees(),
|
angle_start: angle_start.degrees(),
|
||||||
angle_end: angle_end.degrees(),
|
angle_end: angle_end.degrees(),
|
||||||
|
start: Some(angle_start),
|
||||||
|
end: Some(angle_end),
|
||||||
center: center.into(),
|
center: center.into(),
|
||||||
radius,
|
radius,
|
||||||
relative: false,
|
relative: false,
|
||||||
@ -1148,40 +1133,12 @@ async fn inner_tangential_arc(
|
|||||||
to.into()
|
to.into()
|
||||||
}
|
}
|
||||||
TangentialArcData::PointWithTag { to, .. } => {
|
TangentialArcData::PointWithTag { to, .. } => {
|
||||||
args.send_modeling_cmd(
|
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, to)).await?;
|
||||||
id,
|
|
||||||
ModelingCmd::ExtendPath {
|
|
||||||
path: sketch_group.id,
|
|
||||||
segment: kittycad::types::PathSegment::TangentialArcTo {
|
|
||||||
angle_snap_increment: None,
|
|
||||||
to: kittycad::types::Point3D {
|
|
||||||
x: to[0],
|
|
||||||
y: to[1],
|
|
||||||
z: 0.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
*to
|
*to
|
||||||
}
|
}
|
||||||
TangentialArcData::Point(to) => {
|
TangentialArcData::Point(to) => {
|
||||||
args.send_modeling_cmd(
|
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, to)).await?;
|
||||||
id,
|
|
||||||
ModelingCmd::ExtendPath {
|
|
||||||
path: sketch_group.id,
|
|
||||||
segment: kittycad::types::PathSegment::TangentialArcTo {
|
|
||||||
angle_snap_increment: None,
|
|
||||||
to: kittycad::types::Point3D {
|
|
||||||
x: to[0],
|
|
||||||
y: to[1],
|
|
||||||
z: 0.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
*to
|
*to
|
||||||
}
|
}
|
||||||
@ -1207,6 +1164,20 @@ async fn inner_tangential_arc(
|
|||||||
Ok(new_sketch_group)
|
Ok(new_sketch_group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tan_arc_to(sketch_group: &SketchGroup, to: &[f64; 2]) -> ModelingCmd {
|
||||||
|
ModelingCmd::ExtendPath {
|
||||||
|
path: sketch_group.id,
|
||||||
|
segment: kittycad::types::PathSegment::TangentialArcTo {
|
||||||
|
angle_snap_increment: None,
|
||||||
|
to: Point3D {
|
||||||
|
x: to[0],
|
||||||
|
y: to[1],
|
||||||
|
z: 0.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Data to draw a tangential arc to a specific point.
|
/// Data to draw a tangential arc to a specific point.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -1247,24 +1218,8 @@ async fn inner_tangential_arc_to(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let delta = [to[0] - from.x, to[1] - from.y];
|
let delta = [to[0] - from.x, to[1] - from.y];
|
||||||
|
|
||||||
let id = uuid::Uuid::new_v4();
|
let id = uuid::Uuid::new_v4();
|
||||||
|
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, &delta)).await?;
|
||||||
args.send_modeling_cmd(
|
|
||||||
id,
|
|
||||||
ModelingCmd::ExtendPath {
|
|
||||||
path: sketch_group.id,
|
|
||||||
segment: kittycad::types::PathSegment::TangentialArcTo {
|
|
||||||
angle_snap_increment: None,
|
|
||||||
to: kittycad::types::Point3D {
|
|
||||||
x: delta[0],
|
|
||||||
y: delta[1],
|
|
||||||
z: 0.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let current_path = Path::ToPoint {
|
let current_path = Path::ToPoint {
|
||||||
base: BasePath {
|
base: BasePath {
|
||||||
|
|||||||
@ -1,86 +1,57 @@
|
|||||||
use std::f64::consts::PI;
|
use std::f64::consts::PI;
|
||||||
|
|
||||||
|
use kittycad::types::Angle;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{Point2d, SourceRange},
|
executor::{Point2d, SourceRange},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, PartialOrd, PartialEq, Debug)]
|
/// Get the angle between these points
|
||||||
pub struct Angle {
|
pub fn between(a: Point2d, b: Point2d) -> Angle {
|
||||||
degrees: f64,
|
let x = b.x - a.x;
|
||||||
|
let y = b.y - a.y;
|
||||||
|
normalize(Angle::from_radians(y.atan2(x)))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<kittycad::types::Angle> for Angle {
|
/// Normalize the angle
|
||||||
fn from(angle: kittycad::types::Angle) -> Self {
|
pub fn normalize(angle: Angle) -> Angle {
|
||||||
match angle.unit {
|
let deg = angle.degrees();
|
||||||
kittycad::types::UnitAngle::Degrees => Self::from_degrees(angle.value),
|
let result = ((deg % 360.0) + 360.0) % 360.0;
|
||||||
kittycad::types::UnitAngle::Radians => Self::from_radians(angle.value),
|
Angle::from_degrees(if result > 180.0 { result - 360.0 } else { result })
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Angle {
|
/// Gives the ▲-angle between from and to angles (shortest path), use radians.
|
||||||
const ZERO: Self = Self { degrees: 0.0 };
|
///
|
||||||
/// Make an angle of the given degrees.
|
/// Sign of the returned angle denotes direction, positive means counterClockwise 🔄
|
||||||
pub fn from_degrees(degrees: f64) -> Self {
|
/// # Examples
|
||||||
Self { degrees }
|
///
|
||||||
}
|
/// ```
|
||||||
/// Make an angle of the given radians.
|
/// use std::f64::consts::PI;
|
||||||
pub fn from_radians(radians: f64) -> Self {
|
///
|
||||||
Self::from_degrees(radians.to_degrees())
|
/// use kcl_lib::std::utils::Angle;
|
||||||
}
|
///
|
||||||
/// Get the angle in degrees
|
/// assert_eq!(
|
||||||
pub fn degrees(&self) -> f64 {
|
/// Angle::delta(Angle::from_radians(PI / 8.0), Angle::from_radians(PI / 4.0)),
|
||||||
self.degrees
|
/// Angle::from_radians(PI / 8.0)
|
||||||
}
|
/// );
|
||||||
/// Get the angle in radians
|
/// ```
|
||||||
pub fn radians(&self) -> f64 {
|
#[allow(dead_code)]
|
||||||
self.degrees.to_radians()
|
pub fn delta(from_angle: Angle, to_angle: Angle) -> Angle {
|
||||||
}
|
let norm_from_angle = normalize_rad(from_angle.radians());
|
||||||
/// Get the angle between these points
|
let norm_to_angle = normalize_rad(to_angle.radians());
|
||||||
pub fn between(a: Point2d, b: Point2d) -> Self {
|
let provisional = norm_to_angle - norm_from_angle;
|
||||||
let x = b.x - a.x;
|
|
||||||
let y = b.y - a.y;
|
|
||||||
Self::from_radians(y.atan2(x)).normalize()
|
|
||||||
}
|
|
||||||
/// Normalize the angle
|
|
||||||
pub fn normalize(self) -> Self {
|
|
||||||
let angle = self.degrees();
|
|
||||||
let result = ((angle % 360.0) + 360.0) % 360.0;
|
|
||||||
Self::from_degrees(if result > 180.0 { result - 360.0 } else { result })
|
|
||||||
}
|
|
||||||
/// Gives the ▲-angle between from and to angles (shortest path), use radians.
|
|
||||||
///
|
|
||||||
/// Sign of the returned angle denotes direction, positive means counterClockwise 🔄
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::f64::consts::PI;
|
|
||||||
///
|
|
||||||
/// use kcl_lib::std::utils::Angle;
|
|
||||||
///
|
|
||||||
/// assert_eq!(
|
|
||||||
/// Angle::delta(Angle::from_radians(PI / 8.0), Angle::from_radians(PI / 4.0)),
|
|
||||||
/// Angle::from_radians(PI / 8.0)
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn delta(from_angle: Self, to_angle: Self) -> Self {
|
|
||||||
let norm_from_angle = normalize_rad(from_angle.radians());
|
|
||||||
let norm_to_angle = normalize_rad(to_angle.radians());
|
|
||||||
let provisional = norm_to_angle - norm_from_angle;
|
|
||||||
|
|
||||||
if provisional > -PI && provisional <= PI {
|
if provisional > -PI && provisional <= PI {
|
||||||
return Angle::from_radians(provisional);
|
return Angle::from_radians(provisional);
|
||||||
}
|
|
||||||
if provisional > PI {
|
|
||||||
return Angle::from_radians(provisional - 2.0 * PI);
|
|
||||||
}
|
|
||||||
if provisional < -PI {
|
|
||||||
return Angle::from_radians(provisional + 2.0 * PI);
|
|
||||||
}
|
|
||||||
Angle::ZERO
|
|
||||||
}
|
}
|
||||||
|
if provisional > PI {
|
||||||
|
return Angle::from_radians(provisional - 2.0 * PI);
|
||||||
|
}
|
||||||
|
if provisional < -PI {
|
||||||
|
return Angle::from_radians(provisional + 2.0 * PI);
|
||||||
|
}
|
||||||
|
Angle::ZERO
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|||||||
@ -1530,10 +1530,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
||||||
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
||||||
|
|
||||||
"@kittycad/lib@^0.0.43":
|
"@kittycad/lib@^0.0.45":
|
||||||
version "0.0.43"
|
version "0.0.45"
|
||||||
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.43.tgz#b93c0961200cf327f5ac6491be1ca01f9edc321c"
|
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.45.tgz#42cd58df8e5712600d7ecf25713a2b67bc649bdc"
|
||||||
integrity sha512-Pe/PQfZ8BWEDOm4dkY4tcPcuCSh2mQPe/W8RvJ6PQNTlB7bmjAj0234pVyG+8zrKKsJC9nq4ye7CZoaXEfUSTg==
|
integrity sha512-zfc42vg4BtZKklmz1nCJALdegdGE/lmCx3Cj0bE1ZTBEdxcra+Dpd77froglf0dzOzBGa4ONOHh5Ixh7/69aSQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
node-fetch "3.3.2"
|
node-fetch "3.3.2"
|
||||||
openapi-types "^12.0.0"
|
openapi-types "^12.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user